PyGTKでファイルマネージャからファイルアイコンをドラッグ・アンド・ドロップを受け取る(概要と簡単な例)
GUIアプリケーションにおいて、ドラッグ・アンド・ドロップ(以下D&D)をすることでデータをアプリケーション間でやりとりしやすくなることがある。
PyGTKでもD&Dを扱うことは可能で、ここで扱うのは受け取り側のアプリケーションでファイルマネージャのアイコンなど、URIリスト形式のデータをどう処理するかについて。
ドロップを受け取るときのシグナル
(ウィンドウを含む)GUI部品はデータのドロップを受け取ると「drag_data_received」というシグナルが起こることになっていて、それに関連付けたハンドラ(関数)が呼ばれる。
シグナル「drag_data_received」を処理するハンドラの引数とその中身
D&Dを受け取るとき、ハンドラにはそのGUI部品に関するオブジェクト自身以外に多くの引数が渡される。
http://www.pygtk.org/pygtk2tutorial/sec-DNDMethods.html#id2873419
の「drag_data_received_cb」に書かれているのが全ての引数(「data」は追加で渡すユーザデータで任意となる)。一部は単なる値だが、context(gtk.gdk.DragContext)とselection(gtk.SelectionData)はオブジェクトとなっている。
gtk.gdk.DragContext
gtk.gdk.DragContextオブジェクトのデータはD&Dのそれ自体に関する情報をメンバ変数に持っている。「action」「actions」「suggested_action」「targets」などがあるが、完全な一覧はgtk.gdk.DragContextオブジェクトのページを参照。
部品側がD&Dを受け取るための設定
シグナルに対するハンドラにD&Dが起こったときの処理を記述し、これと関連付けただけではD&Dは受け取れず、受け取るGUI部品側でD&Dを受け取れるための指定が別に必要となる。
gtk.Widgetオブジェクトのメンバ関数drag_dest_set()とdrag_dest_unset()でその設定を行い、前者では条件を指定して受け取り可能な状態に設定し、後者は受け取り不可能な状態に戻す(入力ファイルに対する処理を開始してから終了するまでの間、新しくアイコンがドロップされるのをブロックするのに使える)。
drag_dest_set()の引数については下の例やリファレンスを参照。
例
下のコードを実行し、ウィンドウにGUIファイルマネージャからアイコンをD&Dすると、このD&Dに関する各種情報を端末に表示する。
[任意]ファイル名: dnd-urllistreceivetest.py
#! /usr/bin/python # -*- encoding: utf-8 -*- import sys import os try: import pygtk pygtk.require("2.0") except: pass try: import gtk except: print >> sys.stderr, "Error: PyGTK is not installed" sys.exit(1) class MainWindow(gtk.Window): """ メインウィンドウ """ # 種類の識別番号 TARGET_TYPE_TEXT_URI_LIST = 12345 # 受け付ける種類を識別番号と結びつけたタプルのリスト # 2番目には受け付けるドラッグ元の範囲を示す値を指定 # 0: 制限なし # gtk.TARGET_SAME_APP: 同一アプリ内 # gtk.TARGET_SAME_WIDGET: 同一部品内 dnd_list = [('text/uri-list', 0, TARGET_TYPE_TEXT_URI_LIST),] def __init__(self): gtk.Window.__init__(self) # 必須 self.connect("delete_event", gtk.main_quit) # 閉じるボタンで終了 # D&D受け取り時のシグナル self.connect("drag_data_received", self.on_drag_data_received) # gtk.DEST_DEFAULT_MOTIONはドロップする項目の種類をチェック # gtk.DEST_DEFAULT_HIGHLIGHTはドロップできる項目を乗せたときに表示を変更 # gtk.DEST_DEFAULT_DROPはドロップが正常にできたかをチェック # gtk.gdk.ACTION_COPYはコピー操作のアイコン self.drag_dest_set(gtk.DEST_DEFAULT_MOTION | gtk.DEST_DEFAULT_HIGHLIGHT | gtk.DEST_DEFAULT_DROP, self.dnd_list, gtk.gdk.ACTION_COPY) def on_drag_data_received(self, widget, context, x, y, selection, info, time): """ 項目がウィンドウにドロップされたときの処理 """ # 引数をそのまま表示 print "context: %s\nx: %d\ny: %d\nselection: %s\ninfo: %d\ntime: %d" \ % (context, x, y, selection, info, time) # ドラッグ・コンテキストの一部メンバ変数 print "action: %s\nactions: %s\nsuggested_action: %s\ntargets: %s" \ % (context.action, context.actions, context.suggested_action, context.targets) # 生のselection.data print "selection.data: [%s]" % selection.data class PyGTKDndUrilistReceiveTest: """ D&DによるURIリスト形式の受け取りテスト """ def main(self): win = MainWindow() # 今回はウィンドウの中には何も入れないで表示 win.show_all() gtk.main() if __name__ == "__main__": app = PyGTKDndUrilistReceiveTest() app.main()
ファイルマネージャによっては若干挙動が異なり、また、Wine上のWindows版PyGTKでも別の部分で挙動が変わる。詳しくは別記事で扱うが、このあたりをアプリケーションや環境によって動作が変わらないようにコード側で工夫をする必要がある。
関連記事:
- PyGTKでファイルマネージャからファイルアイコンをドラッグ・アンド・ドロップを受け取る(ファイルマネージャや環境による挙動の違いについて)
- PyGTKでファイルマネージャからファイルアイコンをドラッグ・アンド・ドロップを受け取る(URIリストの加工と環境による違いの吸収)
参考URL: