El método drag_source_set() especifica un conjunto de tipos objetivo para una operación de arrastrar en un control.
widget.drag_source_set(start_button_mask, targets, actions) |
Los parámetros significan lo siguiente:
widget especifica el control fuente
start_button_mask especifica una máscara de bits de los botones que pueden empezar a arrastrar (por ejemplo BUTTON1_MASK).
targets especifica una lista de los tipos de datos objetivos que se manejarán.
actions especifica un máscara de bits de las acciones posibles para arrastrar desde esta ventana.
El parámetro targets es una lista de tuplas similar a:
(target, flags, info) |
target especifica una cadena de caracteres que representa el tipo de arrastre.
flags restringe la aplicación del arrastre. flags puede ser 0 (sin limitación del ámbito) o las siguientes constantes:
gtk.TARGET_SAME_APP # El objetivo sólo se puede seleccionar para arrastres dentro de una única aplicación. gtk.TARGET_SAME_WIDGET # El objetivo sólo se puede seleccionar para arrastres dentro del mismo control. |
info es un identificador entero asignado por la aplicación.
Si no es necesario que un control siga siendo el orígen de operaciones arrastrar-y-soltar, el método drag_source_unset() se puede usar para eliminar un conjunto de tipos de objetivos arrastrar-y-soltar.
widget.drag_source_unset() |
Las siguientes señales se envian al control fuente durante una operación de arrastrar-y-soltar.
Tabla 22.1. Señales del Control Fuente
| drag_begin (comienzo de arrastre) | def drag_begin_cb(widget, drag_context, data): |
| drag_data_get (obtención de datos de arrastre) | def drag_data_get_cb(widget, drag_context, selection_data, info, time, data): |
| drag_data_delete (eliminación de datos de arrastre) | def drag_data_delete_cb(widget, drag_context, data): |
| drag_end (fin de arrastre) | def drag_end_cb(widget, drag_context, data): |
El manejador de señal "drag-begin" se puede usar para configurar algunas condiciones iniciales tales como el icono de arrastre usando para ello uno de los siguientes métodos del la clase Widget: drag_source_set_icon(), drag_source_set_icon_pixbuf(), drag_source_set_icon_stock(). El manejador de señal "drag-end" puede usarse para deshacer las acciones del manejador de señal "drag-begin".
El manejador de señal "drag-data-get" debería devolver los datos de arrastre que coincidan con el objetivo especificado por info. Rellena gtk.gdk.SelectionData con los datos de arrastre.
El manejador de señal "drag-delete" se usa para borrar los datos de arrastre de una acción gtk.gdk.ACTION_MOVE tras haberlos copiado.
drag_dest_set() especifica que este control puede ser destino de operaciones arrastrar-y-soltar y define los tipos que admite.
drag_dest_unset() especifica que el control no puede recibir más operaciones arrastrar-y-soltar.
widget.drag_dest_set(flags, targets, actions)
widget.drag_dest_unset()
|
flags especifica qué acciones debe realizar GTK+ por parte del control cuando se suelte algo en él. Los valores posibles son:
| gtk.DEST_DEFAULT_MOTION | Si está activado para un control, GTK+ comprobará si el arrastre se corresponde con algún objetivo y acción del control cuando se arrastre por encima de él. Entonces GTK+ llamará a drag_status() según corresponda. |
| gtk.DEST_DEFAULT_HIGHLIGHT | Si está activado para un control, GTK+ resaltará el control siempre que el arrastre esté encima del mismo y el formato y la acción sean aceptables. |
| gtk.DEST_DEFAULT_DROP | Si está activado para un control, GTK+ comprobará si el arrastre se corresponde con algún objetivo y acción de dicho control. Si es así, GTK+ llamará a drag_data_get() de parte del control. No importa si el soltar tiene éxito o no, GTK+ llamará a drag_finish(). Si la acción fue mover y el arrastre tuvo éxito, entonces se pasará TRUE como argumento delete (borrar) a drag_finish(). |
| gtk.DEST_DEFAULT_ALL | Si está activo, especifica que todas las acciones anteriores deben ejecutarse. |
targets es una lista de tuplas de información de objetivos tal y como se describe más arriba.
actions es una máscara de bits de las posibles acciones que realizar cuando se arrastre sobre este control. Los valores posibles se pueden componer con la operación OR y son los siguientes:
gtk.gdk.ACTION_DEFAULT # acción predeterminada
gtk.gdk.ACTION_COPY # acción copiar
gtk.gdk.ACTION_MOVE # acción mover
gtk.gdk.ACTION_LINK # acción enlazar
gtk.gdk.ACTION_PRIVATE # acción privada
gtk.gdk.ACTION_ASK # acción preguntar
|
targets y actions son ignoradas si flags no contiene gtk.DEST_DEFAULT_MOTION o gtk.DEST_DEFAULT_DROP. En este caso la aplicación debe manejar las señales "drag-motion" y "drag-drop".
El manejador de señal "drag-motion" debe determinar si los datos de arrastre son apropiados comparando para ello los objetivos del destino con los objetivos gtk.gdk.DragContext y opcionalmente examinando los datos de arrastre llamando el método drag_get_data() method. Se debe llamar al método gtk.gdk.DragContext. drag_status() para actualizar el estado de drag_context.
El manejador de señal "drag-drop" debe determinar el objetivo que corresponda usando el método del control drag_dest_find_target() y después solicitar los datos de arrastre mediante el método del control drag_get_data(). Los datos estarán disponibles en el manejador "drag-data-received".
El programa dragtargets.py muestra todos los posibles objetivos de una operación de arrastre en un control de tipo etiqueta (label):
1 #!/usr/local/env python
2
3 import pygtk
4 pygtk.require('2.0')
5 import gtk
6
7 def motion_cb(wid, context, x, y, time):
8 context.drag_status(gtk.gdk.ACTION_COPY, time)
9 return True
10
11 def drop_cb(wid, context, x, y, time):
12 l.set_text('\n'.join([str(t) for t in context.targets]))
13 return True
14
15 w = gtk.Window()
16 w.set_size_request(200, 150)
17 w.drag_dest_set(0, [], 0)
18 w.connect('drag_motion', motion_cb)
19 w.connect('drag_drop', drop_cb)
20 w.connect('destroy', lambda w: gtk.main_quit())
21 l = gtk.Label()
22 w.add(l)
23 w.show_all()
24
25 gtk.main()
|
El programa crea una ventana que se configura como destino de arrastre para ningún objetivo y ninguna acción poniendo las banderas (flags) a cero. Se conectan los manejadores motion_cb() y drop_cb() a las señales "drag-motion" y "drag-drop" respectivamente. El manejador motion_cb() configura el estado de arrastre para que se permita soltar. drop_cb() modifica el texto de la etiqueta a una cadena de caracteres que contenga los objetivos de arrastre e ignora los datos de tal modo que la acción de soltar no se completa en ningún caso..
Durante una operación arrastrar-y-soltar se envian las siguientes señales al control destino.
Tabla 22.2. Señales del Control Destino
| drag_motion (movimiento de arrastre) | def drag_motion_cb(widget, drag_context, x, y, time, data): |
| drag_drop (arrastre soltado) | def drag_drop_cb(widget, drag_context, x, y, time, data): |
| drag_data_received (datos recibidos) | def drag_data_received_cb(widget, drag_context, x, y, selection_data, info, time, data): |
El programa de ejemplo dragndrop.py muestra el uso de arrastrar y soltar en una aplicación. Un botón con un icono xpm (en gtkxpm.py) es el origen del arrastre y proporciona tanto texto como datos xpm. Un control de disposición es el destino para soltar el xpm mientras que un botón es el destino para soltar el texto. La figura Figura 22.1, “Ejemplo de Arrastrar y Soltar” ilustra la ventana del programa tras soltar el xpm en el control de disposición y el texto en el botón:
El código fuente de dragndrop.py es:
1 #!/usr/bin/env python
2
3 # ejemplo dragndrop.py
4
5 import pygtk
6 pygtk.require('2.0')
7 import gtk
8 import string, time
9
10 import gtkxpm
11
12 class DragNDropExample:
13 HEIGHT = 600
14 WIDTH = 600
15 TARGET_TYPE_TEXT = 80
16 TARGET_TYPE_PIXMAP = 81
17 fromImage = [ ( "text/plain", 0, TARGET_TYPE_TEXT ),
18 ( "image/x-xpixmap", 0, TARGET_TYPE_PIXMAP ) ]
19 toButton = [ ( "text/plain", 0, TARGET_TYPE_TEXT ) ]
20 toCanvas = [ ( "image/x-xpixmap", 0, TARGET_TYPE_PIXMAP ) ]
21
22 def layout_resize(self, widget, event):
23 x, y, width, height = widget.get_allocation()
24 if width > self.lwidth or height > self.lheight:
25 self.lwidth = max(width, self.lwidth)
26 self.lheight = max(height, self.lheight)
27 widget.set_size(self.lwidth, self.lheight)
28
29 def makeLayout(self):
30 self.lwidth = self.WIDTH
31 self.lheight = self.HEIGHT
32 box = gtk.VBox(gtk.FALSE,0)
33 box.show()
34 table = gtk.Table(2, 2, gtk.FALSE)
35 table.show()
36 box.pack_start(table, gtk.TRUE, gtk.TRUE, 0)
37 layout = gtk.Layout()
38 self.layout = layout
39 layout.set_size(self.lwidth, self.lheight)
40 layout.connect("size-allocate", self.layout_resize)
41 layout.show()
42 table.attach(layout, 0, 1, 0, 1, gtk.FILL|gtk.EXPAND,
43 gtk.FILL|gtk.EXPAND, 0, 0)
44 # se crean las barras de desplazamiento que se empaquetan en la tabla
45 vScrollbar = gtk.VScrollbar(None)
46 vScrollbar.show()
47 table.attach(vScrollbar, 1, 2, 0, 1, gtk.FILL|gtk.SHRINK,
48 gtk.FILL|gtk.SHRINK, 0, 0)
49 hScrollbar = gtk.HScrollbar(None)
50 hScrollbar.show()
51 table.attach(hScrollbar, 0, 1, 1, 2, gtk.FILL|gtk.SHRINK,
52 gtk.FILL|gtk.SHRINK,
53 0, 0)
54 # indicamos que las barras de desplazamiento usen los ajustes del control disposición
55 vAdjust = layout.get_vadjustment()
56 vScrollbar.set_adjustment(vAdjust)
57 hAdjust = layout.get_hadjustment()
58 hScrollbar.set_adjustment(hAdjust)
59 layout.connect("drag_data_received", self.receiveCallback)
60 layout.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
61 gtk.DEST_DEFAULT_HIGHLIGHT |
62 gtk.DEST_DEFAULT_DROP,
63 self.toCanvas, gtk.gdk.ACTION_COPY)
64 self.addImage(gtkxpm.gtk_xpm, 0, 0)
65 button = gtk.Button("Text Target")
66 button.show()
67 button.connect("drag_data_received", self.receiveCallback)
68 button.drag_dest_set(gtk.DEST_DEFAULT_MOTION |
69 gtk.DEST_DEFAULT_HIGHLIGHT |
70 gtk.DEST_DEFAULT_DROP,
71 self.toButton, gtk.gdk.ACTION_COPY)
72 box.pack_start(button, gtk.FALSE, gtk.FALSE, 0)
73 return box
74
75 def addImage(self, xpm, xd, yd):
76 hadj = self.layout.get_hadjustment()
77 vadj = self.layout.get_vadjustment()
78 style = self.window.get_style()
79 pixmap, mask = gtk.gdk.pixmap_create_from_xpm_d(
80 self.window.window, style.bg[gtk.STATE_NORMAL], xpm)
81 image = gtk.Image()
82 image.set_from_pixmap(pixmap, mask)
83 button = gtk.Button()
84 button.add(image)
85 button.connect("drag_data_get", self.sendCallback)
86 button.drag_source_set(gtk.gdk.BUTTON1_MASK, self.fromImage,
87 gtk.gdk.ACTION_COPY)
88 button.show_all()
89 # ajustamos según el desplazamientos de la disposición - la posición del evento
90 # es relativo a la zona visible, no al tamaño del control disposición
91 self.layout.put(button, int(xd+hadj.value), int(yd+vadj.value))
92 return
93
94 def sendCallback(self, widget, context, selection, targetType, eventTime):
95 if targetType == self.TARGET_TYPE_TEXT:
96 now = time.time()
97 str = time.ctime(now)
98 selection.set(selection.target, 8, str)
99 elif targetType == self.TARGET_TYPE_PIXMAP:
100 selection.set(selection.target, 8,
101 string.join(gtkxpm.gtk_xpm, '\n'))
102
103 def receiveCallback(self, widget, context, x, y, selection, targetType,
104 time):
105 if targetType == self.TARGET_TYPE_TEXT:
106 label = widget.get_children()[0]
107 label.set_text(selection.data)
108 elif targetType == self.TARGET_TYPE_PIXMAP:
109 self.addImage(string.split(selection.data, '\n'), x, y)
110
111 def __init__(self):
112 self.window = gtk.Window(gtk.WINDOW_TOPLEVEL)
113 self.window.set_default_size(300, 300)
114 self.window.connect("destroy", lambda w: gtk.main_quit())
115 self.window.show()
116 layout = self.makeLayout()
117 self.window.add(layout)
118
119 def main():
120 gtk.main()
121
122 if __name__ == "__main__":
123 DragNDropExample()
124 main()
|