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