[pygtk] Selecting and moving objects on a layout

Loic BERTHE loic.berthe at free.fr
Sat Mar 25 06:00:19 WST 2006


    Hi,

I'm trying to make a canvas where I can put objects, move them by
drag'n'drop,
and select them by drawing a box with the mouse or by clicking on them.
But :

    - I've no idea how to draw a box with the mouse and how to deal with
selection
    - My first try to implement moving by drag'n'drop seems pretty ugly,

As a little example is better than a long description, you can find the
code below

Have you any idea or  link that could help me ?

Critics and  comments on the code  would be very welcome.

Regards,

-- 
Elby

#!/usr/bin/env python
# -*- coding: iso-8859-15 -*-
#
# A first try to make a Canvas where you can move objects by drag'n'drop
#

import pygtk
pygtk.require('2.0')
import gtk


# Drag'n'Drop
TARGET_TYPE_NDDE = 80
fromNode = [ ( "node_move", 0, TARGET_TYPE_NDDE ),]
toCanvas = [ ( "node_move", 0, TARGET_TYPE_NDDE ),]

#-------------------------------------------------------------------------------
class Node:

    counter = 1

    tiny_pixbuf = gtk.gdk.pixbuf_new_from_xpm_data([
        "26 26 5 1",
        "  c black",
        ". c grey",
        "o c yellow",
        "X c blue",
        "- c None",
        "---------        ---------",
        "-------   oooooo   -------",
        "-----   oooooooooo   -----",
        "----  oooooooooooooo  ----",
        "---  oooooooooooooooo  ---",
        "--  oooooooooooooooooo  --",
        "-- oooooooooooooooooooo  -",
        "-  ooooooooooooooooooooo -",
        "- oooooooooooooooooooooo  ",
        "  ooooo   oooooo.    .ooo ",
        " ooooo XXX oooo. XXXX ooo ",
        " ooooo XXX oooo XXXXXX oo ",
        " ooooo. X .oooo XXXXXX oo ",
        " oooooo. .ooooo XXXXXX oo ",
        " oooooooooooooo. XXXX ooo ",
        " ooooooooooooooo.    .ooo ",
        "  ooooooooooooooooooooooo ",
        "- ooo.oooooooooooooooooo  ",
        "-  oo. .oooooooooo.  ooo -",
        "-- ooo   .ooooooo.  ooo  -",
        "--  ooo XX         .oo  --",
        "---  ooo  XXXXXXX .oo  ---",
        "----  oooo       ooo  ----",
        "-----   oooooooooo   -----",
        "------    oooooo    ------",
        "--------          --------"
        ])


    def __init__(self,name=None,Type='Data',x=50, y=50):
        self.Type = Type
        self.x    = x
        self.y    = y
        self.name = name or "%s%d" % (Type,self.counter)
        self.__class__.counter += 1

        # image
        self.Image_EventBox = gtk.EventBox()
        self.Image_EventBox.set_border_width(0)

        self.Image = gtk.Image()
        self.Image.set_from_pixbuf(self.tiny_pixbuf)
        self.Image_EventBox.add(self.Image)

        self.Image.show()
        self.Image_EventBox.show()

        # Label
        self.Label_EventBox = gtk.EventBox()
        self.Label_EventBox.set_border_width(0)

        self.Label = gtk.Label(self.name)
        self.Label.set_justify(gtk.JUSTIFY_CENTER)
        self.Label.set_size_request(width=66, height=-1)
        self.Label.set_line_wrap(True)
        self.Label_EventBox.add(self.Label)

        # Drag'n'drop
        self.Image_EventBox.connect("drag_begin", self.begin_Callback)
        self.Image_EventBox.connect("drag_data_get", self.send_Callback)
        self.Image_EventBox.drag_source_set(gtk.gdk.BUTTON1_MASK,fromNode,
                               gtk.gdk.ACTION_COPY)

        self.Label.show()
        self.Label_EventBox.show()

    def begin_Callback(self, widget, context):
        widget.drag_source_set_icon_pixbuf(self.tiny_pixbuf)

    def send_Callback(self, widget, context, selection, targetType, time):
        if targetType == TARGET_TYPE_NDDE:
            selection.set(selection.target, 8, str(id(self)))

    def put_on_layout(self,layout):
        layout.put(self.Image_EventBox, self.x, self.y)
        layout.put(self.Label_EventBox, self.x-15, self.y+28)

    def move_on_layout(self,layout, x,y):
        self.x = int(x + layout.get_hadjustment().value)
        self.y = int(y + layout.get_vadjustment().value)
        layout.move(self.Image_EventBox, self.x   , self.y)
        layout.move(self.Label_EventBox, self.x-15, self.y+28)

    def __repr__(self):
        return self.name

#-------------------------------------------------------------------------------

class My_App:
    HEIGHT = 600
    WIDTH  = 600

    def __init__(self):
        self.NodeList =[]

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

    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
        table = gtk.Table(2, 2, False)
        table.show()
        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)

        # drag n drop signals
        layout.connect("drag_data_received", self.receiveCallback)
        layout.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
                                  gtk.DEST_DEFAULT_HIGHLIGHT |
                                  gtk.DEST_DEFAULT_DROP,
                                  toCanvas, gtk.gdk.ACTION_COPY)
        return table

    def receiveCallback(self, widget, context, x, y, selection, targetType,
                        time):
        if targetType == TARGET_TYPE_NDDE:
            node_id = int(selection.data)
            for node in self.NodeList :
                if id(node) == node_id :
node.move_on_layout(self.layout,x,y)

    def add_node(self, node):
        self.NodeList.append(node)
        node.put_on_layout(self.layout)

if __name__ == "__main__":
    app = My_App()
    NodeList =  [
        Node(name = "very very very very happy ", Type='Data'  , x=50 ,
y=50),
        Node(name='happy',Type='App', x=150, y=100),
        Node(Type='Data', x=250, y=200),
        Node(Type='Data', x=50, y=200),
        ]
    for node in NodeList :
        app.add_node(node)

    gtk.main()

# vim: set et sts=4 sw=4:



More information about the pygtk mailing list