21. Dra-och-släpp¶
Observera
Versioner av PyGObject < 3.0.3 innehåller ett fel som inte låter dra-och-släpp fungera korrekt. Därför krävs en version av PyGObject >= 3.0.3 för att följande exempel ska fungera.
Att konfigurera dra-och-släpp mellan komponenter består i att välja en dragkälla (komponenten som användaren startar dragningen från) med metoden Gtk.Widget.drag_source_set()
, välja ett dragmål (komponenten som användaren släpper på) med metoden Gtk.Widget.drag_dest_set()
och sedan hantera de relevanta signalerna för båda komponenterna.
Istället för att använda Gtk.Widget.drag_source_set()
och Gtk.Widget.drag_dest_set()
så kräver vissa specialiserade komponenter användningen av specifika funktioner (så som Gtk.TreeView
och Gtk.IconView
).
Ett enkelt dra-och-släpp kräver bara att källan ansluter till signalen ”drag-data-get” och att målet ansluter till signalen ”drag-data-received”. Mer komplexa saker som specifika släppområden och anpassade dragikoner kommer kräva att du ansluter till ytterligare signaler och interagerar med Gdk.DragContext
-objektet det tillhandahåller.
För att överföra data mellan källan och målet behöver du interagera med variabeln Gtk.SelectionData
som tillhandahålls i signalerna ”drag-data-get” och ”drag-data-received” med get- och set-metoderna för Gtk.SelectionData
.
21.1. Målfält¶
För att dragningens källa och mål ska få veta vilka data de tar emot och skickar krävs en gemensam lista över Gtk.TargetEntry
. Ett Gtk.TargetEntry
beskriver ett datastycke som kommer sändas av dragkällan och tas emot av dragmålet.
Det finns två sätt att lägga till Gtk.TargetEntry
till en källa och ett mål. Om dra-och-släppet är enkelt och varje målfält är av olika typ så kan du använda gruppen av metoder omnämnda här
.
Om du behöver mer än en typ av data eller vill göra mer komplexa saker med dessa data kommer du behöva skapa ditt Gtk.TargetEntry
med metoden Gtk.TargetEntry.new()
.
21.2. Dragkällsignaler¶
Namn |
När den sänds ut |
Vanligt syfte |
---|---|---|
drag-begin |
Användaren startar en dragning |
Konfigurera dragikon |
drag-data-get |
Då dragningsdata begärs av målet |
Överför dragningsdata från källan till målet |
drag-data-delete |
Då en dragning med åtgärden Gdk.DragAction.MOVE slutförts |
Ta bort data från källan för att slutföra ”flytten” |
drag-end |
Då dragningen slutförts |
Gör allt som gjorts i drag-begin ogjort |
21.3. Dragmålsignaler¶
Namn |
När den sänds ut |
Vanligt syfte |
---|---|---|
drag-motion |
Dragikon flyttar över ett släppområde |
Tillåt endast vissa områden att släppas till |
drag-drop |
Ikon släpps på ett dragområde |
Tillåt endast vissa områden att släppas till |
drag-data-received |
När dragningsdata tas emot av målet |
Överför dragningsdata från källan till målet |
21.4. Exempel¶

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk, Gdk, GdkPixbuf
(TARGET_ENTRY_TEXT, TARGET_ENTRY_PIXBUF) = range(2)
(COLUMN_TEXT, COLUMN_PIXBUF) = range(2)
DRAG_ACTION = Gdk.DragAction.COPY
class DragDropWindow(Gtk.Window):
def __init__(self):
super().__init__(title="Drag and Drop Demo")
vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6)
self.add(vbox)
hbox = Gtk.Box(spacing=12)
vbox.pack_start(hbox, True, True, 0)
self.iconview = DragSourceIconView()
self.drop_area = DropArea()
hbox.pack_start(self.iconview, True, True, 0)
hbox.pack_start(self.drop_area, True, True, 0)
button_box = Gtk.Box(spacing=6)
vbox.pack_start(button_box, True, False, 0)
image_button = Gtk.RadioButton.new_with_label_from_widget(None, "Images")
image_button.connect("toggled", self.add_image_targets)
button_box.pack_start(image_button, True, False, 0)
text_button = Gtk.RadioButton.new_with_label_from_widget(image_button, "Text")
text_button.connect("toggled", self.add_text_targets)
button_box.pack_start(text_button, True, False, 0)
self.add_image_targets()
def add_image_targets(self, button=None):
targets = Gtk.TargetList.new([])
targets.add_image_targets(TARGET_ENTRY_PIXBUF, True)
self.drop_area.drag_dest_set_target_list(targets)
self.iconview.drag_source_set_target_list(targets)
def add_text_targets(self, button=None):
self.drop_area.drag_dest_set_target_list(None)
self.iconview.drag_source_set_target_list(None)
self.drop_area.drag_dest_add_text_targets()
self.iconview.drag_source_add_text_targets()
class DragSourceIconView(Gtk.IconView):
def __init__(self):
Gtk.IconView.__init__(self)
self.set_text_column(COLUMN_TEXT)
self.set_pixbuf_column(COLUMN_PIXBUF)
model = Gtk.ListStore(str, GdkPixbuf.Pixbuf)
self.set_model(model)
self.add_item("Item 1", "image-missing")
self.add_item("Item 2", "help-about")
self.add_item("Item 3", "edit-copy")
self.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, [], DRAG_ACTION)
self.connect("drag-data-get", self.on_drag_data_get)
def on_drag_data_get(self, widget, drag_context, data, info, time):
selected_path = self.get_selected_items()[0]
selected_iter = self.get_model().get_iter(selected_path)
if info == TARGET_ENTRY_TEXT:
text = self.get_model().get_value(selected_iter, COLUMN_TEXT)
data.set_text(text, -1)
elif info == TARGET_ENTRY_PIXBUF:
pixbuf = self.get_model().get_value(selected_iter, COLUMN_PIXBUF)
data.set_pixbuf(pixbuf)
def add_item(self, text, icon_name):
pixbuf = Gtk.IconTheme.get_default().load_icon(icon_name, 16, 0)
self.get_model().append([text, pixbuf])
class DropArea(Gtk.Label):
def __init__(self):
Gtk.Label.__init__(self)
self.set_label("Drop something on me!")
self.drag_dest_set(Gtk.DestDefaults.ALL, [], DRAG_ACTION)
self.connect("drag-data-received", self.on_drag_data_received)
def on_drag_data_received(self, widget, drag_context, x, y, data, info, time):
if info == TARGET_ENTRY_TEXT:
text = data.get_text()
print("Received text: %s" % text)
elif info == TARGET_ENTRY_PIXBUF:
pixbuf = data.get_pixbuf()
width = pixbuf.get_width()
height = pixbuf.get_height()
print("Received pixbuf with width %spx and height %spx" % (width, height))
win = DragDropWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
|