[pygtk] Drag and Drop in GTK Drawing Area

Vihan Pandey vihanpandey at gmail.com
Mon Jan 16 20:06:24 WST 2006


Hello,
          i was trying out the drawingarea.py example and trying to use drag
and drop in the same, but i can't figure out how to do so. In the tutorial
dragndrop.py,  we add an xpm image to a button. I wanted to know if we can
try DND without using a button altogether(If possible). Just simply move
discrete objects within the drawing area. I would really appreciate some
help here.

Thanks a lot!

P.S : since i'm here let me specially thank Matthias Bläsing for helping me
get PyGTK 2.8 running with Cairo support.

Thanks again!

-vihan

drawingarea.py :

!/usr/bin/env python

# example drawingarea.py

import pygtk
pygtk.require('2.0')
import gtk
import operator
import time
import string

class DrawingAreaExample:
    def __init__(self):
        window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        window.set_title("Drawing Area Example")
        window.connect("destroy", lambda w: gtk.main_quit())
        self.area = gtk.DrawingArea()
        self.area.set_size_request(400, 300)
        self.pangolayout = self.area.create_pango_layout("")
        self.sw = gtk.ScrolledWindow()
        self.sw.add_with_viewport(self.area)
        self.table = gtk.Table(2,2)
        self.hruler = gtk.HRuler()
        self.vruler = gtk.VRuler()
        self.hruler.set_range(0, 400, 0, 400)
        self.vruler.set_range(0, 300, 0, 300)
        self.table.attach(self.hruler, 1, 2, 0, 1, yoptions=0)
        self.table.attach(self.vruler, 0, 1, 1, 2, xoptions=0)
        self.table.attach(self.sw, 1, 2, 1, 2)
        window.add(self.table)
        self.area.set_events(gtk.gdk.POINTER_MOTION_MASK |
                             gtk.gdk.POINTER_MOTION_HINT_MASK )
        self.area.connect("expose-event", self.area_expose_cb)
        def motion_notify(ruler, event):
            return ruler.emit("motion_notify_event", event)
        self.area.connect_object("motion_notify_event", motion_notify,
                                 self.hruler)
        self.area.connect_object("motion_notify_event", motion_notify,
                                 self.vruler)
        self.hadj = self.sw.get_hadjustment()
        self.vadj = self.sw.get_vadjustment()
        def val_cb(adj, ruler, horiz):
            if horiz:
                span = self.sw.get_allocation()[3]
            else:
                span = self.sw.get_allocation()[2]
            l,u,p,m = ruler.get_range()
            v = adj.value
            ruler.set_range(v, v+span, p, m)
            while gtk.events_pending():
                gtk.main_iteration()
        self.hadj.connect('value-changed', val_cb, self.hruler, True)
        self.vadj.connect('value-changed', val_cb, self.vruler, False)
        def size_allocate_cb(wid, allocation):
            x, y, w, h = allocation
            l,u,p,m = self.hruler.get_range()
            m = max(m, w)
            self.hruler.set_range(l, l+w, p, m)
            l,u,p,m = self.vruler.get_range()
            m = max(m, h)
            self.vruler.set_range(l, l+h, p, m)
        self.sw.connect('size-allocate', size_allocate_cb)
        self.area.show()
        self.hruler.show()
        self.vruler.show()
        self.sw.show()
        self.table.show()
        window.show()

    def area_expose_cb(self, area, event):
        self.style = self.area.get_style()
        self.gc = self.style.fg_gc[gtk.STATE_NORMAL]

        self.draw_point(10,10)
        self.draw_points(110, 10)
        self.draw_line(210, 10)
        self.draw_lines(310, 10)
        self.draw_segments(10, 100)
        self.draw_rectangles(110, 100)
        self.draw_arcs(210, 100)
        self.draw_pixmap(310, 100)
        self.draw_polygon(10, 200)
        self.draw_rgb_image(110, 200)

        return True



    def draw_point(self, x, y):
        self.area.window.draw_point(self.gc, x+30, y+30)
        self.pangolayout.set_text("Point")
        self.area.window.draw_layout(self.gc, x+5, y+50, self.pangolayout)
        return


    def draw_points(self, x, y):
        points = [(x+10,y+10), (x+10,y), (x+40,y+30),
                  (x+30,y+10), (x+50,y+10), (x+70,y+5)]
        self.area.window.draw_points(self.gc, points)
        self.pangolayout.set_text("Points")
        self.area.window.draw_layout(self.gc, x+5, y+50, self.pangolayout)
        return



    def draw_line(self, x, y):
        self.area.window.draw_line(self.gc, x+10, y+10, x+20, y+30)
        self.pangolayout.set_text("Line")
        self.area.window.draw_layout(self.gc, x+5, y+50, self.pangolayout)
        return

    def draw_lines(self, x, y):
        points = [(x+10,y+10), (x+10,y), (x+40,y+30),
                  (x+30,y+10), (x+50,y+10)]
        self.area.window.draw_lines(self.gc, points)
        self.pangolayout.set_text("Lines")
        self.area.window.draw_layout(self.gc, x+5, y+50, self.pangolayout)
        return

    def draw_segments(self, x, y):
        segments = ((x+20,y+10, x+20,y+70), (x+60,y+10, x+60,y+70),
            (x+10,y+30 , x+70,y+30), (x+10, y+50 , x+70, y+50))
        self.area.window.draw_segments(self.gc, segments)
        self.pangolayout.set_text("Segments")
        self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
        return

    def draw_rectangles(self, x, y):
        self.area.window.draw_rectangle(self.gc, False, x, y, 80, 70)
        self.area.window.draw_rectangle(self.gc, True, x+10, y+10, 20, 20)
        self.area.window.draw_rectangle(self.gc, True, x+50, y+10, 20, 20)
        self.area.window.draw_rectangle(self.gc, True, x+20, y+50, 40, 10)
        self.pangolayout.set_text("Rectangles")
        self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
        return

    def draw_arcs(self, x, y):
        self.area.window.draw_arc(self.gc, False, x+10, y, 70, 70,
                                  0, 360*64)
        self.area.window.draw_arc(self.gc, True, x+30, y+20, 10, 10,
                                  0, 360*64)
        self.area.window.draw_arc(self.gc, True, x+50, y+20, 10, 10,
                                  0, 360*64)
        self.area.window.draw_arc(self.gc, True, x+30, y+10, 30, 50,
                                  210*64, 120*64)
        self.pangolayout.set_text("Arcs")
        self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
        return

    def draw_pixmap(self, x, y):
        pixmap, mask = gtk.gdk.pixmap_create_from_xpm(
            self.area.window, self.style.bg[gtk.STATE_NORMAL], "gtk.xpm")

        self.area.window.draw_drawable(self.gc, pixmap, 0, 0, x+15, y+25,
                                       -1, -1)
        self.pangolayout.set_text("Pixmap")
        self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
        return

    def draw_polygon(self, x, y):
        points = [(x+10,y+60), (x+10,y+20), (x+40,y+70),
                  (x+30,y+30), (x+50,y+40)]
        self.area.window.draw_polygon(self.gc, True, points)
        self.pangolayout.set_text("Polygon")
        self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
        return

    def draw_rgb_image(self, x, y):
        b = 80*3*80*['\0']
        for i in range(80):
            for j in range(80):
                b[3*80*i+3*j] = chr(255-3*i)
                b[3*80*i+3*j+1] = chr(255-3*abs(i-j))
                b[3*80*i+3*j+2] = chr(255-3*j)
        buff = string.join(b, '')
        self.area.window.draw_rgb_image(self.gc, x, y, 80, 80,
                                 gtk.gdk.RGB_DITHER_NONE, buff, 80*3)
        self.pangolayout.set_text("RGB Image")
        self.area.window.draw_layout(self.gc, x+5, y+80, self.pangolayout)
        return


def main():
    gtk.main()
    return 0

if __name__ == "__main__":
    DrawingAreaExample()
    main()




dragndrop.py :

#!/usr/bin/env python

# example dragndrop.py

import pygtk
pygtk.require('2.0')
import gtk
import string, time

import gtkxpm

class DragNDropExample:
    HEIGHT = 600
    WIDTH = 600
    TARGET_TYPE_TEXT = 80
    TARGET_TYPE_PIXMAP = 81
    fromImage = [ ( "text/plain", 0, TARGET_TYPE_TEXT ),
              ( "image/x-xpixmap", 0, TARGET_TYPE_PIXMAP ) ]
    toButton = [ ( "text/plain", 0, TARGET_TYPE_TEXT ) ]
    toCanvas = [ ( "image/x-xpixmap", 0, TARGET_TYPE_PIXMAP ) ]

    def layout_resize(self, widget, event):
        x, y, width, height = widget.get_allocation()
        if width > self.lwidth or height > self.lheight:
            self.lwidth = max(width, self.lwidth)
            self.lheight = max(height, self.lheight)
            widget.set_size(self.lwidth, self.lheight)

    def makeLayout(self):
        self.lwidth = self.WIDTH
        self.lheight = self.HEIGHT
        box = gtk.VBox(False,0)
        box.show()
        table = gtk.Table(2, 2, False)
        table.show()
        box.pack_start(table, True, True, 0)
        layout = gtk.Layout()
        self.layout = layout
        layout.set_size(self.lwidth, self.lheight)
        layout.connect("size-allocate", self.layout_resize)
        layout.show()
        table.attach(layout, 0, 1, 0, 1, gtk.FILL|gtk.EXPAND,
                     gtk.FILL|gtk.EXPAND, 0, 0)
        # create the scrollbars and pack into the table
        vScrollbar = gtk.VScrollbar(None)
        vScrollbar.show()
        table.attach(vScrollbar, 1, 2, 0, 1, gtk.FILL|gtk.SHRINK,
                     gtk.FILL|gtk.SHRINK, 0, 0)
        hScrollbar = gtk.HScrollbar(None)
        hScrollbar.show()
        table.attach(hScrollbar, 0, 1, 1, 2, gtk.FILL|gtk.SHRINK,
                     gtk.FILL|gtk.SHRINK,
                     0, 0)
        # tell the scrollbars to use the layout widget's adjustments
        vAdjust = layout.get_vadjustment()
        vScrollbar.set_adjustment(vAdjust)
        hAdjust = layout.get_hadjustment()
        hScrollbar.set_adjustment(hAdjust)
        layout.connect("drag_data_received", self.receiveCallback)
        layout.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
                                  gtk.DEST_DEFAULT_HIGHLIGHT |
                                  gtk.DEST_DEFAULT_DROP,
                                  self.toCanvas, gtk.gdk.ACTION_COPY)
        self.addImage(gtkxpm.gtk_xpm, 0, 0)
        button = gtk.Button("Text Target")
        button.show()
        button.connect("drag_data_received", self.receiveCallback)
        button.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
                             gtk.DEST_DEFAULT_HIGHLIGHT |
                             gtk.DEST_DEFAULT_DROP,
                             self.toButton, gtk.gdk.ACTION_COPY)
        box.pack_start(button, False, False, 0)
        return box

    def addImage(self, xpm, xd, yd):
        hadj = self.layout.get_hadjustment()
        vadj = self.layout.get_vadjustment()
        style = self.window.get_style()
        pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(
            self.window.window, style.bg[gtk.STATE_NORMAL], xpm)
        image = gtk.Image()
        image.set_from_pixmap(pixmap, mask)
        button = gtk.Button()
        button.add(image)
        button.connect("drag_data_get", self.sendCallback)
        button.drag_source_set(gtk.gdk.BUTTON1_MASK, self.fromImage,
                               gtk.gdk.ACTION_COPY)
        button.show_all()
        # have to adjust for the scrolling of the layout - event location
        # is relative to the viewable not the layout size
        self.layout.put(button, int(xd+hadj.value), int(yd+vadj.value))
        return

    def sendCallback(self, widget, context, selection, targetType,
eventTime):
        if targetType == self.TARGET_TYPE_TEXT:
            now = time.time()
            str = time.ctime(now)
            selection.set(selection.target, 8, str)
        elif targetType == self.TARGET_TYPE_PIXMAP:
            selection.set(selection.target, 8,
                          string.join(gtkxpm.gtk_xpm, '\n'))

    def receiveCallback(self, widget, context, x, y, selection, targetType,
                        time):
        if targetType == self.TARGET_TYPE_TEXT:
            label = widget.get_children()[0]
            label.set_text(selection.data)
        elif targetType == self.TARGET_TYPE_PIXMAP:
            self.addImage(string.split(selection.data, '\n'), x, y)

    def __init__(self):
        self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
        self.window.set_default_size(300, 300)
        self.window.connect("destroy", lambda w: gtk.main_quit())
        self.window.show()
        layout = self.makeLayout()
        self.window.add(layout)

def main():
    gtk.main()

if __name__ == "__main__":
    DragNDropExample()
    main()
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.daa.com.au/pipermail/pygtk/attachments/20060116/143385f9/attachment-0001.htm


More information about the pygtk mailing list