fc2ブログ

    Max風スピナを作ってみる!(でも一番のお楽しみポイントはカーソルの位置を操作できる事なんだからね! 勘違いしないでよね!)

     突然ではございますが皆様は「3ds Max」をご使用になられた事はございますか?
     3ds MaxはAutodesk社のエンターテイメント向けCGソフトの主力の一角を担っておりまして、同社Mayaと双璧をなすCGソフトでございます。
     その3ds Maxには数値を操作するためのUIとしてスピナを実装しております。このスピナ、一見ただのスピンボックスでございますが、なんと値を操作するインジケータ上でマウスを上下にドラッグ致しますと値をいとも簡単に操作する事ができるという優れ物でございます。

     今回は、現在同じ会社で働いていらっしゃる御茶ノ水先生から
    「Maxのスピナみたいの出来ね~の? マジで」(会話イメージ)
    と言うご相談を頂きまして、Qtを使用したサンプルを作った次第であります。


     そのMax風スピナの肝とも言えますのが
    マウスカーソルが画面の上端(もしくは下端)まで到達すると反対側から現れる
    と言う挙動でございました。
     今回のサンプルではそちらも合わせて実装致しました。少々乱雑なコードではございますが何かの足しにでもと思い、書き記した次第でございます。


     それではサンプルコードを御覧下さい。
    # -*- coding:utf-8 -*-
    
    from PyQt4 import QtGui, QtCore
    import sys
    
    class Spiner( QtGui.QSpinBox ):
        '''Max風スピナクラス'''
        # ボタンによって加速度を変更するための倍率を保持するクラス内変数。
        ButtonFactor = {
            QtCore.Qt.MiddleButton : 10,
            QtCore.Qt.RightButton  : 100,
        }
    
        def __init__( self, parent=None ):
            super( Spiner, self ).__init__( parent )
            self.__Y       = 0          # マウスのY座標保持用変数。
            self.__pressed = None       # クリックされたマウスボタン保持用変数。
    
    
        def repositionCursor( self, y ):
            '''デスクトップの上端または下端に来た際に、反対側へマウスを送る処理。
            また、self.__Yへ現在の座標をセットする。'''
    
            # 現在のデスクトップの矩形データ(QRect)を取得する。
            currentScreenRect = QtGui.qApp.desktop().screenGeometry(
                QtGui.qApp.desktop().screenNumber( QtGui.QCursor().pos() )
            )
            
            # カーソルの下限値。画面の一番上の座標。通常は0だが、マルチデスク
            # トップの場合は値が上下する。
            lowerLimit = currentScreenRect.y()
    
            # カーソルの上限値。スクリーンの高さから下限値を引いた値が実有効サイズ。
            # こちらもマルチデスクトップの場合値が変動する。
            upperLimit = currentScreenRect.height() + lowerLimit - 1
    
            # 引数yの値が上下限値範囲無いの場合は、引数yの値をself.__Yにセットして
            # 終了する。
            if y <= lowerLimit:
                posY = upperLimit - 1
            elif y >= upperLimit:
                posY = lowerLimit + 1
            else:
                self.__Y = y
                return
    
            # マウスカーソルの位置を、新しいY座標の位置へ移動する。
            QtGui.QCursor().setPos( QtGui.QCursor().pos().x(), posY )
    
            # 更新されたY座標をself.__Yへセットして終了する。
            self.__Y = posY
            
            
        def mousePressEvent( self, event ):
            '''マウスをクリックした際のイベント'''
            super( Spiner, self ).mousePressEvent( event )
    
            # マウスカーソルの現在位置を取得し、クラス内変数へ保存する。
            self.__Y = event.globalY()
            # クリックされたボタンを記憶。
            self.__pressed = event.button()
    
    
        def mouseMoveEvent( self, event ):
            '''マウス移動中のイベント'''
            super( Spiner, self ).mouseMoveEvent( event )
    
            # マウスカーソルの現在位置を取得し、最後に記録されたマウスカーソル位置
            # との差分を取得。
            posY       = event.globalY()
            movedValue = self.__Y - posY
            
            # マウスの押されたボタンに応じて加算される数字に倍率をかける。
            # 真中ボタンなら×10、右ボタンなら×100される。
            if self.__pressed in self.ButtonFactor:
                movedValue *= self.ButtonFactor[self.__pressed]
    
            # 差分を現在のスピンボックスの値に加算してからセットする。
            self.setValue( self.value() + movedValue )
    
            self.repositionCursor( posY )
    
    
        def mouseReleaseEvent( self, event ):
            '''マウスを話した際のイベント'''
            super( Spiner, self ).mouseReleaseEvent( event )
    
    
    # メインウィンドウのクラス
    class MainWindow( QtGui.QWidget ):
        def __init__( self, parent=None ):
            super( MainWindow, self ).__init__( parent )
            layout = QtGui.QVBoxLayout( self )
            
            # Max風スピナを作成し、初期化。----------------------------------------
            spiner = Spiner()
            spiner.setMinimum( -100000 )    # スピンボックスの下限値を設定。
            spiner.setMaximum( 100000 )     # スピンボックスの上限値を設定。
            # ---------------------------------------------------------------------
            
            layout.addWidget( spiner )
    
    
    if __name__ == '__main__':
        app = QtGui.QApplication( sys.argv )
        win = MainWindow()
        win.show()
    
        sys.exit( app.exec_() )
    
     今回のコードではデスクトップの情報を取得するためにQDesktopWidgetを使用しております。QDesktopWidgetに関しましては以前当ブログでも取り扱っております。
    QtでDesktopの情報をゲットする
     興味がございましたら合わせてご観覧頂ければ幸い至極でございます。

     さて、今回のコードでは
    mousePressEvent
    mouseMoveEvent
    を上書きする事で目的の動作を達成致しております。
     それぞれのメソッドは、名前の通りマウスをクリックした際とマウスをドラッグしている際にお好みの挙動を記述する事が出来ると言うものでございます。

     詳細はソースコードを見て頂くとして、簡単にご説明させて頂きますと

    壱.mousePressEvent内にて現在のマウスカーソルのY座標、押されたマウスのボタンをクラス内変数へ保存

    弐.mouseMoveEvent内にて先ほどのマウスカーソルのY座標と現在のY座標の差分をとり、その差分をスピナの値に加算

     と言った工程を繰り返しております。


     また、マウスが画面の上端または下端へ到達してしまった際には
    QtGui.QCursor().setPos( x, y )
    
    にてカーソルを反対側へ移動するよう操作してございます。
     こちらの機能を使用致しますと、マウスカーソルを自由な位置へ移動させる事が出来るという大変な優れ物でございまして、ちょっとしたツールなどで活用できるのではないのでしょうか。


     以上、簡単ではございますがMax風スピナを作成するサンプルでございました。
    スポンサーサイト



    コメントの投稿

    非公開コメント

    プロフィール

    Eske

    Author:Eske
    萌えイラストレーターを目指す3DCGイラストレーター。
    現在ポケモンカードゲーム、ガンダムトライエイジ、ガンダムコンクエスト、妖怪ウォッチとりつきカードゲームなどで3DCGを使用したイラストレーターとして参加中。

    主にここでは日々気づいたメモなんかを残してます。
    イラストのお仕事も受け付けております。ココのメールアドレスからご連絡できますので、お気軽にご相談下さい。

    最新記事
    最新コメント
    カテゴリ
    最新トラックバック
    月別アーカイブ
    検索フォーム
    リンク
    QRコード
    QR