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:
| 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
|
| 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. |
| 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 |
| 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()