19. Drag and Drop

Note

Versions of PyGObject < 3.0.3 contain a bug which does not allow drag and drop to function correctly. Therefore a version of PyGObject >= 3.0.3 is required for the following examples to work.

Setting up drag and drop between widgets consists of selecting a drag source (the widget which the user starts the drag from) with the Gtk.Widget.drag_source_set() method, selecting a drag destination (the widget which the user drops onto) with the Gtk.Widget.drag_dest_set() method and then handling the relevant signals on both widgets.

Instead of using Gtk.Widget.drag_source_set() and Gtk.Widget.drag_dest_set() some specialised widgets require the use of specific functions (such as Gtk.TreeView and Gtk.IconView).

A basic drag and drop only requires the source to connect to the “drag-data-get” signal and the destination to connect to the “drag-data-received” signal. More complex things such as specific drop areas and custom drag icons will require you to connect to additional signals and interact with the Gdk.DragContext object it supplies.

In order to transfer data between the source and destination, you must interact with the Gtk.SelectionData variable supplied in the “drag-data-get” and “drag-data-received” signals using the Gtk.SelectionData get and set methods.

19.1. Target Entries

To allow the drag source and destination to know what data they are receiving and sending, a common list of Gtk.TargetEntry's are required. A Gtk.TargetEntry describes a piece of data that will be sent by the drag source and received by the drag destination.

There are two ways of adding Gtk.TargetEntry's to a source and destination. If the drag and drop is simple and each target entry is of a different type, you can use the group of methods mentioned here.

If you require more than one type of data or wish to do more complex things with the data, you will need to create the Gtk.TargetEntry's using the Gtk.TargetEntry.new() method.

19.2. Drag and Drop Methods and Objects

class Gtk.Widget
drag_source_set(start_button_mask, targets, actions)

Sets the widget to be a drag source.

start_button_mask are a combination of Gdk.ModifierType masks which sets which buttons must be pressed for a drag to occur. targets is a list of Gtk.TargetEntry's which describe the data to be passed between source and destination. actions are a combination Gdk.DragAction masks to show possible drag actions.

drag_dest_set(flags, targets, actions)

Sets the widget to be a drag destination.

flags are a combination of Gtk.DestDefaults masks which configures the processes which occur on a drag site. targets is a list of Gtk.TargetEntry's which describe the data to be passed between source and destination. actions are a combination Gdk.DragAction masks to show possible drag actions.

drag_source_add_text_targets()
drag_dest_add_text_targets()

Add a Gtk.TargetEntry to the drag source/destination which contains a piece of text.

drag_source_add_image_targets()
drag_dest_add_image_targets()

Add a Gtk.TargetEntry to the drag source/destination which contains a GdkPixbuf.Pixbuf.

drag_source_add_uri_targets()
drag_dest_add_uri_targets()

Add a Gtk.TargetEntry to the drag source/destination which contains a list of URIs.

class Gtk.TargetEntry
static new(target, flags, info)

Creates a new target entry.

target is a string describing the type of data the target entry describes.

flags controls under which conditions will the data be transferred in a drag and drop and is a combination of the Gtk.TargetFlags values:

  • Gtk.TargetFlags.SAME_APP - Only transferred in the same application
  • Gtk.TargetFlags.SAME_WIDGET - Only transferred within the same widget
  • Gtk.TargetFlags.OTHER_APP - Only transferred in a different application
  • Gtk.TargetFlags.OTHER_WIDGET - Only transferred within a different widget

info is an ID which the application can use to determine between different pieces of data contained in a drag and drop operation.

class Gtk.SelectionData
get_text()

Returns the contents of the text contained in selection data

set_text(text)

Sets the contents of the text contained in selection data to text

get_pixbuf()

Returns the pixbuf contained in selection data

set_pixbuf(pixbuf)

Sets the pixbuf contained in selection data to pixbuf

19.3. Drag Source Signals

Name When it is emitted Common Purpose
drag-begin User starts a drag Set-up drag icon
drag-data-get When drag data is requested by the destination Transfer drag data from source to destination
drag-data-delete When a drag with the action Gdk.DragAction.MOVE is completed Delete data from the source to complete the ‘move’
drag-data-end When the drag is complete Undo anything done in drag-begin

19.4. Drag Destination Signals

Name When it is emitted Common Purpose
drag-motion Drag icon moves over a drop area Allow only certain areas to be dropped onto
drag-drop Icon is dropped onto a drag area Allow only certain areas to be dropped onto
drag-data-received When drag data is received by the destination Transfer drag data from source to destination

19.5. Example

_images/drag_and_drop_example.png
  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
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):
        Gtk.Window.__init__(self, 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")
        self.add_item("Item 2", "gtk-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, "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("delete-event", Gtk.main_quit)
win.show_all()
Gtk.main()

Project Versions

Table Of Contents

Previous topic

18. Clipboard

Next topic

20. Glade and Gtk.Builder

This Page