PyGObject: Drag and Drop
Drag and drop
Impostare un Drag and Drop tra widgets consiste nel selezionare un Drag Source,
ovvero il widget dal quale cominceremo il Drag, selezionare un Drag Destination,
ovvero il widget sul quale eseguiremo il Drop, gestire i segnali su entrambi i widget.
In maniera molto generica, un Drag Source viene selezionato con il metodo
Gtk.Widget.drag_source_set(),
mentre il Drag Destination, viene selezionato con il metodo
Gtk.Widget.drag_dest_set().
Alcuni widget specializzati, come Gtk.TreeView and Gtk.IconView, usano metodi specifici per questa
operazione.
Un drag and drop basico richiede che il source sia connesso al segnale “drag-data-get”
e il destination sia connesso al segnale “drag-data-received”.
Se invece abbiamo bisogno di maggior complessità, come aree di drop specifiche, o icone di drag
personalizzate, sarà necessaria la connessione a segnali aggiuntivi e dovremo interagire con
l’oggetto Gdk.DragContext.
Per trasferire dati tra source e destination, dobbiamo
interagire con la variabile Gtk.SelectionData fornita nei segnali “drag-data-get”
e “drag-data-received”, usando i metodi getter e setter di Gtk.SelectionData.
Target Entries
Per permettere al drag source e al destination di conoscere quali dati stanno rispettivamente
spedendo e ricevendo, è necessaria una lista comune di Gtk.TargetEntry.
Possiamo costruirla creando direttamente una lista di istanze Gtk.TargetEntry, o creando
un oggetto Gtk.TargetList:
>>> targets = [ ... Gtk.TargetEntry.new("STRING", Gtk.TargetFlags.SAME_APP, 0), ... Gtk.TargetEntry.new("image/png", Gtk.TargetFlags.SAME_APP, 1), ... ] >>> targets = Gtk.TargetList.new([ ... Gtk.TargetEntry.new("STRING", Gtk.TargetFlags.SAME_APP, 0), ... Gtk.TargetEntry.new("image/png", Gtk.TargetFlags.SAME_APP, 1), ... ]) >>> targets.find(Gdk.Atom.intern_static_string("STRING")) (True, info=0)
Oppure utilizzare i metodi che mette a disposizione la classe Gtk.TargetList:
Gtk.TargetList.add_image_targets(info, writable), Gtk.TargetList.add_text_targets(info), ecc.
Una volta creata la lista targets e abilitati i widget all’operazione di drag and drop con
i metodi enable_model_drag_source(button_mask, targets, actions) ed
enable_model_drag_dest(targets, actions), non resta che associarla ai widget
source e destination, preposti al drag and drop, con i metodi drag_dest_set_target_list(targets) e
drag_source_set_target_list(targets).
>>> drag_source = Gtk.IconView() >>> drag_source.enable_model_drag_source(start_button_mask=Gdk.ModifierType.BUTTON1_MASK, targets=[], ... actions=Gdk.DragAction.COPY) >>> drag_dest = Gtk.IconView() >>> drag_dest.enable_model_drag_dest(targets=[], actions=Gdk.DragAction.COPY) >>> drag_source.drag_source_set_target_list(targets) >>> drag_dest.drag_dest_set_target_list(targets)
Segnali
Drag Source Signals:
Name | Emesso | Scopo |
---|---|---|
drag-begin | Quando lo User unizia il drag | Setta la icona di drag |
drag-data-get | Quando i dati sono richiesti dal destination | Trasferisce i dati del drag da source a destination |
drag-data-delete | Quando un drag con la action Gdk.DragAction.MOVE è completata | Elimina i dati dal source per completare il “move” |
drag-end | Quando il drag è completo | Anunlla quello fatto in drag-begin |
Drag Destination Signals:
Name | Emesso | Scopo |
---|---|---|
drag-motion | Quando la icon Drag va sopra un’area di drop | Permette di eseguire il drop solo su certe aree |
drag-drop | Quando la icona viene lasciata su un’area di drop | Permette di eseguire il drop solo su certe aree |
drag-data-received | Quando i dati di drag sono ricevuti dal destination | Trasferisce i dati del drag da source a destination |
Ecco un codice di esempio:
import gi gi.require_version('Gtk', '3.0') from gi.repository import Gtk, Gdk, GdkPixbuf class GWindow(Gtk.Window): def __init__(self): super().__init__(title="Drag and Drop Example") self.set_default_size(300, 400) label_source = Gtk.Label(label="Drag source") label_destination = Gtk.Label(label="Drop Area") self.drag_source = DragSourceIconView() # Source widget self.drag_dest = DragDestination() # Destination widget button_img = Gtk.RadioButton.new_with_label_from_widget( None, "Drag image only") button_text = Gtk.RadioButton.new_with_label_from_widget( button_img, "Drag text only") # layout vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) label_box = Gtk.Box(spacing=12) label_box.pack_start(label_source, True, True, 0) label_box.pack_start(label_destination, True, True, 0) dnd_box = Gtk.Box(spacing=5) dnd_box.pack_start(self.drag_source, True, True, 0) dnd_box.pack_start(self.drag_dest, True, True, 0) button_box = Gtk.Box(spacing=6) button_box.pack_start(button_img, True, False, 0) button_box.pack_start(button_text, True, False, 0) vbox.pack_start(label_box, True, False, 0) vbox.pack_start(dnd_box, True, False, 0) vbox.pack_start(button_box, True, False, 0) self.add(vbox) # bindings button_img.connect("toggled", self.add_image_targets) button_text.connect("toggled", self.add_text_targets) self.add_image_targets() def add_image_targets(self, button=None): targets = Gtk.TargetList.new([]) targets.add_image_targets(info=1, writable=True) self.drag_dest.drag_dest_set_target_list(targets) self.drag_source.drag_source_set_target_list(targets) def add_text_targets(self, button=None): targets = Gtk.TargetList.new([]) targets.add_text_targets(info=0) self.drag_dest.drag_dest_set_target_list(targets) self.drag_source.drag_source_set_target_list(targets) class DragSourceIconView(Gtk.IconView): def __init__(self): super().__init__() self.set_text_column(0) self.set_pixbuf_column(1) model = Gtk.ListStore(str, GdkPixbuf.Pixbuf) self.set_model(model) for text, icon in [("Item 1", "image-missing"), ("Item 2", "help-about"), ("Item 3", "edit-copy")]: pixbuf = Gtk.IconTheme.get_default().load_icon(icon, 32, 0) self.get_model().append([text, pixbuf]) self.enable_model_drag_source( start_button_mask=Gdk.ModifierType.BUTTON1_MASK, targets=[], actions=Gdk.DragAction.COPY) # bindings 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 == 0: text = self.get_model().get_value(selected_iter, 0) data.set_text(text, -1) elif info == 1: pixbuf = self.get_model().get_value(selected_iter, 1) data.set_pixbuf(pixbuf) class DragDestination(Gtk.IconView): def __init__(self): super().__init__() self.set_text_column(0) self.set_pixbuf_column(1) model = Gtk.ListStore(str, GdkPixbuf.Pixbuf) self.set_model(model) self.enable_model_drag_dest(targets=[], actions=Gdk.DragAction.COPY) # bindings self.connect("drag-data-received", self.on_drag_data_received) def on_drag_data_received(self, w, context, x, y, data, info, time, *args): model = w.get_model() pixbuf = text = None if info == 0: text = data.get_text() # None if 'only image' is toggled elif info == 1: pixbuf = data.get_pixbuf() # None if 'only text' is toggled model.append([text, pixbuf]) if __name__ == "__main__": win = GWindow() win.connect("destroy", Gtk.main_quit) win.show_all() Gtk.main()
link di riferimento:
Commenti recenti