Paepoi » PyGObject Tips » Gtk(PyGObject) Tips | ドラッグ・アンド・ドロップ
Gtk(PyGObject) Tips | ドラッグ・アンド・ドロップ
# 最終更新日 2019.09.08
2019 年現在の仕様に追記と書き換え。
マウス右ボタンでファイルアイコンや選択範囲等を掴んで移動、別の場所で離す行為。
ドラッグ・アンド・ドロップでは長いので以下 DnD とします。
ようするにファイルマネージャからのファイルドロップ。
同様に Nautilus からファイルをドロップするとそのファイルのフルパスが IFS 区切りで流し込まれる。
それと同様に振り分けを行なうには以下のように。
GtkTargetEntry に text/plain を指定し GtkSelectionData に文字列を突っ込むだけです。
コレを True にするだけで DnD による並べ替えが可能になる。
更にデフォルトでアプリケーション間の DnD が可能。
GTK2 と GTK3 間でも、更に Qt アプリ間でも可能だったりします。
たとえば Gedit で文字列選択して Firefox や Chrome のタブバーにドラッグしてください。
矢印アイコンが出た所でドロップすると検索されます、筆者はよくやります。
又ファイルをドロップすると file:/// で始まる text/uri-list が文字列で流し込まれる。
ただ改行コード(Nautilus は CRLF)も流し込まれるので注意。
ちなみに Cocoa の NSTextField でもフルパスが流し込まれます。
ということでコレに関しては何もする必要が無い。
2019 年現在の仕様に追記と書き換え。
マウス右ボタンでファイルアイコンや選択範囲等を掴んで移動、別の場所で離す行為。
ドラッグ・アンド・ドロップでは長いので以下 DnD とします。
ファイルのドロップ
ほとんどの人が text/uri-list のドロップ以外は利用しないと思う。ようするにファイルマネージャからのファイルドロップ。
#!/usr/bin/env python3 import sys, gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk, GLib class Win(Gtk.ApplicationWindow): ''' drag_dest_add_uri_targets は GtkWidget のメソッド この例はウインドウ全体をターゲットにしていますが個別にもできる ''' def __init__(self, app): Gtk.ApplicationWindow.__init__(self, application=app, title='Py') # これだけでいいです self.drag_dest_add_uri_targets() # self.label = Gtk.Label(label='ファイルをドロップしてね') self.add(self.label) self.show_all() def do_drag_data_received(self, context, x, y, data, info, time): ''' data: GtkSelectionData ''' uris = data.get_uris() l = [] for uri in uris: # URI なのでフルパス名に変換 fn = GLib.filename_from_uri(uri)[0] # ディレクトリ名を取り除く l.append(GLib.path_get_basename(fn)) self.label.set_text('\n'.join(l)) class App(Gtk.Application): def __init__(self): Gtk.Application.__init__(self) def do_startup(self): Gtk.Application.do_startup(self) Win(self) def do_activate(self): self.props.active_window.present() app = App() app.run(sys.argv)
文字列のドロップ
gnome-terminal に Gedit で文字列選択しドロップするとその選択文字列が流し込まれる。同様に Nautilus からファイルをドロップするとそのファイルのフルパスが IFS 区切りで流し込まれる。
それと同様に振り分けを行なうには以下のように。
#!/usr/bin/env python3 import sys, gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk, GLib class Win(Gtk.ApplicationWindow): ''' get_text メソッドでドロップされた文字列は取得できます ファイルのドロップと振り分けするには以下のように ''' def __init__(self, app): Gtk.ApplicationWindow.__init__(self, application=app, title='Py') # ファイル self.drag_dest_add_uri_targets() # 文字列 self.drag_dest_add_text_targets() # self.label = Gtk.Label(label='ファイル又は選択文字列をドロップ') self.add(self.label) self.show_all() def do_drag_data_received(self, context, x, y, data, info, time): ''' data: GtkSelectionData ''' name = data.get_data_type().name() # タイトルバーで確認 self.props.title = name # 振り分け if name == 'UTF8_STRING': s = data.get_text() self.label.set_text(s) elif name == 'text/uri-list': uris = data.get_uris() l = [] for uri in uris: fn = f"'{GLib.filename_from_uri(uri)[0]}'" l.append(fn) self.label.set_text(' '.join(l)) class App(Gtk.Application): def __init__(self): Gtk.Application.__init__(self) def do_startup(self): Gtk.Application.do_startup(self) Win(self) def do_activate(self): self.props.active_window.present() app = App() app.run(sys.argv)
文字列等のドラッグ
ココでは GtkTreeView にある文字列を別アプリにドラッグできるサンプルを以下に。GtkTargetEntry に text/plain を指定し GtkSelectionData に文字列を突っ込むだけです。
#!/usr/bin/env python3 import sys, gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk, Gdk class Win(Gtk.ApplicationWindow): ''' TreeView で選択して検索ボックス等にドロップ ''' def __init__(self, app): Gtk.ApplicationWindow.__init__(self, application=app, title='Py') # TreeView liststore = Gtk.ListStore.new([str]) for s in ['Suzuki V-Strom', 'Suzuki Hayabusa', 'Suzuki Katana', 'GSX-S1000']: liststore.append([s]) cell = Gtk.CellRendererText() column = Gtk.TreeViewColumn(title='YouTube') column.pack_start(cell, True) column.add_attribute(cell, 'text', 0) treeview = Gtk.TreeView(model=liststore) treeview.append_column(column) # Drag Source src = Gtk.TargetEntry.new('text/plain', 0, 0) treeview.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, [src], Gdk.DragAction.COPY) treeview.connect('drag-data-get', self.on_drag_data_get) # self.add(treeview) self.show_all() def on_drag_data_get(self, widget, context, data, info, time): ''' GtkSelectionData にデータを入れるとドロップターゲットに情報が渡る ''' selection = widget.get_selection() model, it = selection.get_selected() text = model.get_value(it, 0) data.set_text(text, -1) class App(Gtk.Application): def __init__(self): Gtk.Application.__init__(self) def do_startup(self): Gtk.Application.do_startup(self) Win(self) def do_activate(self): self.props.active_window.present() app = App() app.run(sys.argv)
reorderable
GtkTreeView, GtkNotebook には reorderable プロパティがある。コレを True にするだけで DnD による並べ替えが可能になる。
#!/usr/bin/env python3 import sys, gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk, GLib#, Gdk class Win(Gtk.ApplicationWindow): ''' TreeView ''' def __init__(self, app): Gtk.ApplicationWindow.__init__(self, application=app, title='Py') # TreeView cell = Gtk.CellRendererText() column = Gtk.TreeViewColumn() column.pack_start(cell, True) column.add_attribute(cell, 'text', 0) store = Gtk.ListStore.new([str]) store.append(['このリストは']) store.append(['DnD で']) store.append(['並べ替えできます']) tree = Gtk.TreeView(model=store, headers_visible=False, reorderable=True) tree.append_column(column) # Notebook note = Gtk.Notebook() page2 = Gtk.Label(label='次のページ') page3 = Gtk.Label(label='最後のページ') note.append_page(tree, Gtk.Label(label='このタブは')) note.append_page(page2, Gtk.Label(label='DnD で')) note.append_page(page3, Gtk.Label(label='並べ替えできます')) # Notebook は Child Property note.child_set_property(tree, 'reorderable', True) note.child_set_property(page2, 'reorderable', True) note.child_set_property(page3, 'reorderable', True) self.add(note) self.show_all() class App(Gtk.Application): def __init__(self): Gtk.Application.__init__(self) def do_startup(self): Gtk.Application.do_startup(self) Win(self) def do_activate(self): self.props.active_window.present() app = App() app.run(sys.argv)
組み込み機能
GtkEntry, GtkTextView では秀丸のような DnD 編集は作成した時点で可能。更にデフォルトでアプリケーション間の DnD が可能。
GTK2 と GTK3 間でも、更に Qt アプリ間でも可能だったりします。
たとえば Gedit で文字列選択して Firefox や Chrome のタブバーにドラッグしてください。
矢印アイコンが出た所でドロップすると検索されます、筆者はよくやります。
又ファイルをドロップすると file:/// で始まる text/uri-list が文字列で流し込まれる。
ただ改行コード(Nautilus は CRLF)も流し込まれるので注意。
ちなみに Cocoa の NSTextField でもフルパスが流し込まれます。
ということでコレに関しては何もする必要が無い。
Copyright(C) sasakima-nao All rights reserved 2002 --- 2024.