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 --- 2025.