🐈‍⬛

Python + Kivy で作ってみた【Ⅲ】

2023/06/26に公開

マウスイベント

PDF画像をマウスでつかみ、そして引きずることで
任意の場所を表示するようにする

マウスでつかむ ➡️ マウスダウン
引きずる ➡️ マウスドラッグ

これらの処理をpythonコード部に記述していく

マウスダウン

マウスダウンのイベントメソッド on_touch_down
ViewAreaWidgetクラス内に記述する

def on_touch_down( self, touch ) :
    touch.ud[ "start_x" ] = touch.x
    touch.ud[ "start_y" ] = touch.y

マウスダウンした座標は、引数のtouchオブジェクトの
xプロパティとyプロパティにある

これをtouchオブジェクトのudプロパティに保存する
このプロパティは辞書型で任意のキーを設定して値を保持できる
キー値は何でもよいので、「start_x」と「start_y」とした

「定数型」がない!

キー値はマウスドラッグでも使うので、定数型を定義して持たせたい
が、しかし!
pythonには定数型がない _| ̄|○
変数名を工夫して定数とわからせればよいというが、
間違って代入してしまったら値が変わってしまう

Googl先生に何か良い手段はないかとお伺いを立ててみる
。。。
。。。
。。。
ふと目にとまったのが、列挙型
数値に名前をつけてわかりやすくするアレ
その列挙型だが、pythonではひと味もふた味も違っている

class TouchInfo( Enum ) :
    X = ( auto(), 'start_x' )
    Y = ( auto(), 'start_y' )

    def __init__( self, id, name ) -> None:
        self.id     = id
        self.p_name = str( name )

このように列挙型クラス(?)を定義して
TouchInfo.X.p_nameと呼び出すと「start_x」と返してくれる

なんとも大がかりな仕込みだが、定数型の替わりになるならまぁいいか…

本当は、TouchInfo.X.nameとしたかったのだが、pythonが許してくれない
また、TouchInfo.X.p_nameを使う先で、string型以外お断り!といわれたから
str( name )と記述している

なかなか、pythonは気難しい言語のようだ(小声)

マウスドラッグ

マウスドラッグのイベントメソッド on_touch_move
ViewAreaWidgetクラス内に記述する

def on_touch_move( self, touch ) :
    move_x = touch.x - touch.ud[ TouchInfo.X.p_name ]
    if( ( self.image_x + move_x < 0 ) and ( self.image_x + move_x > -( self.image_width - self.width ) ) ) :
        self.image_x += move_x
        touch.ud[ TouchInfo.X.p_name ] = touch.x

    move_y = touch.y - touch.ud[ TouchInfo.Y.p_name ]
    if( ( self.image_y + move_y < 0 ) and ( self.image_y + move_y > -( self.image_height - self.height ) ) ) :
        self.image_y += move_y
        touch.ud[ TouchInfo.Y.p_name ] = touch.y

上下左右の移動量を算出し、PDF画像の表示位置(image_x、image_y)を変更する
また、動かしすぎて真っ白にならないように、PDF画像サイズで制限を設ける

一見、うまく動くように見えるが挙動が不自然に感じる
それは、ヘッダーやフッターをクリック、ドラッグしても画像が動くから

ここはどこ?

なぜそういう挙動になるかというと、ヘッダー、フッターをクリック、ドラッグしても
ViewAreaWidgetに記述しているマウスイベントのイベントメソッドが反応するから

つまり、\underbar{\text{どこでマウスイベントが発生したかを判断しないといけない}}
そこで、ある座標(x,y)がwidget内かを判断してくれる「collide_point」を使う

マウスダウン、マウスドラッグのイベントメソッドに追記する

def on_touch_down( self, touch ) :
    if( self.collide_point( touch.x, touch.y ) ) :
        touch.ud[ "start_x" ] = touch.x
        touch.ud[ "start_y" ] = touch.y

def on_touch_move( self, touch ) :
    if( self.collide_point( touch.x, touch.y ) ) :
        move_x = touch.x - touch.ud[ TouchInfo.X.p_name ]
        if( ( self.image_x + move_x < 0 ) and ( self.image_x + move_x > -( self.image_width - self.width ) ) ) :
            self.image_x += move_x
            touch.ud[ TouchInfo.X.p_name ] = touch.x

        move_y = touch.y - touch.ud[ TouchInfo.Y.p_name ]
        if( ( self.image_y + move_y < 0 ) and ( self.image_y + move_y > -( self.image_height - self.height ) ) ) :
            self.image_y += move_y
            touch.ud[ TouchInfo.Y.p_name ] = touch.y

これで、いかにもPDF画像をマウスでつかんで動かしているようになった

PDFビューワーとしては基本的な機能を実装できた
次回は付加的な機能を考え、追加していこう…

Discussion