今日も見に来てくださって、ありがとうございます。石川さんです。
先日、tkinterモジュールのソースコードを眺めていたら、dnd.py
というファイルがありましてちょっと、おお、と思ったので記録しておきます。dndというからにはドラッグ・アンド・ドロップでしょ。
動作確認
ぼくは、Anacondaを使っているので、C:\ProgramData\Anaconda3\Lib\tkinter
にモジュールがあって、そこにこのdnd.pyファイルがあります。ソースを見ると、最後の方にありました、テスト用に直接実行できるコードです。
if __name__ == '__main__': test()
さっそく実行してみました。
ソースコード
ソースコードを追加したかったのですが、みなさんのフォルダにもあるはずなのと、(ぼくの環境は、C:\ProgramData\Anaconda3\Lib\tkinter\dnd.py
です。)、著作権的にも問題があると思いますので、今回はそちらをご覧ください。
解説
ソースコードは下から見ていくとよさそうですね。まずは、ルートのTk
をインスタンス化してから、その後、Tester
クラスを使ってウィンドウを三つ作成しています。この中にはそれぞれCanvas
が作られてありますね。そして、次にIcon
クラスのインスタンスを三つ作って、それぞれそのウィンドウのCanvas
にattach
を実行する、という流れですね。attach
では、引数で受け取ったCanvas
にLabel
をつくって、それからマウスの第一ボタンが押されたときの処理としてpress
が登録されています。
press
では、dnd
モジュールの最初に定義されているdnd_start
が呼び出されていて、ここでDndHandler
によってラップされたインスタンスが作成されます。DndHandler
の初期化の処理で、マウスのボタンがリリースされたときのイベントの処理にon_release
が登録され、<Motion>
イベントの処理にon_motion
が登録されています。要するにマウスが動くたびにon_motion
が呼び出されて、マウスのボタンを離したときにon_release
が呼び出されるようにしました、ということですね。あ、あと、カーソルが"hand2"
に変更されているように見えます。
このマウスが動くたびに呼び出されるon_motion
は、処理中にターゲットのCanvas
が変更されていない間はdnd_motion
を呼び出すことでキャンバス内のラベルを移動させています。ターゲットのCanvas
が変更されたときは、dnd_leave
とdnd_enter
がそれぞれ変更前のCanvas
と変更後のCanvas
で呼び出されて、ドラッグ・アンド・ドロップ実現しています。
最後にマウスのボタンが離されたときに、イベントが削除されたりカーソルを元に戻したりしたあとに、dnd_commit
を呼び出して終了処理をしています。
まとめ
ドラッグアンドドロップは、実装するのに、こんなに複雑なことをしないといけないのですねぇ。今回はざっと眺めただけなのでよいですけど、自分で同じ機能を実現するのは、かなり苦労しそうです。
“Python tkinter GUI プログラミング ドラッグ・アンド・ドロップ” への1件の返信