Proporcionar la selección es un poco más complicado. Se deben registrar los manejadores que se llamarán cuando se solicite la selección. Para cada par selección-objetivo a manejar, se debe hacer una llamada a:
widget.selection_add_target(selection,target,info)
widget (control), selection
(selección), y target (objetivo) identifican las peticiones
que gestionará este manejador. Cuando llegue una petición para una selección, se
llamará a la señal "selection_get". info es un entero
que se puede usar como identificador para el objetivo específico dentro
de la retrollamada.
La retrollamada tiene la siguiente signatura:
def selection_get(widget, selection_data, info, time):
El argumento gtk.SelectionData es el mismo que
antes, pero en esta ocasión se deben rellenar los campos
type, format y data.
(El campo format es importante aquí, ya que el servidor X
lo usa para saber si el campo data necesita que se le cambie
el orden de sus bytes o no. Normalmente será 8 - un caracter - ó 32 - un
entero). Esto se hace llamando al método:
selection_data.set(type,format,data)
Este método de PyGTK sólo puede tratar datos de cadenas de caracteres,
por lo que data debe cargarse en una cadena Python pero
format tendrá el tamaño apropiado para los datos
(por ejemplo 32 para átomos y enteros, 8 para cadenas). Los módulos Python
struct o StringIO pueden servir
para convertir datos que no son cadenas de caracteres a cadenas de caracteres.
Por ejemplo, se puede convertir una lista de enteros en una cadena y ponerlos
en el campo selection_data así:
ilist = [1, 2, 3, 4, 5]
data = apply(struct.pack, ['%di'%len(ilist)] + ilist)
selection_data.set("INTEGER", 32, data)
El siguiente método fija los datos de la selección a partir de dicha cadena:
selection_data.set_text(str,len)
Cuando la usuaria lo solicite, se debe reclamar la posesión de la selección llamando a:
result = widget.selection_owner_set(selection,time=0L)
result será TRUE (verdadero) si el programa
reclama la selección selection con éxito. Si otra aplicación reclama
la posesión de selection, entonces llegará un evento
"selection_clear_event".
Como ejemplo de proporcionar la selección, el programa setselection.py
añade la funcionalidad de selección a un botón biestado que está dentro de una
gtk.EventBox. (Se necesita una
gtk.Eventbox porque la selección debe asociarse a una
gtk.gdk.Window y un gtk.Button
es un control sin ventana en GTK+ 2.0.). Cuando se pulsa el botón biestado el
programa reclama la selección primaria. El único objetivo soportado (aparte de
algunos objetivos que proporciona la propia GTK+ como "TARGETS"), es el
objetivo "STRING". Al solicitar este objetivo se devuelve una
representación en cadena de caracteres de la hora actual. La figura
Figura 21.2, “Ejemplo de Fijar la Selección” muestra la ventana del programa cuando
éste ha conseguido la posesión de la selección primaria:
El código fuente de setselection.py es:
1 #!/usr/bin/env python
2
3 # ejemplo setselection.py
4
5 import pygtk
6 pygtk.require('2.0')
7 import gtk
8 import time
9
10 class SetSelectionExample:
11 # Retrollamada cuando la usuaria conmuta la selección
12 def selection_toggled(self, widget, window):
13 if widget.get_active():
14 self.have_selection = window.selection_owner_set("PRIMARY")
15 # si la solicitud de la selección falla, se devuelve el botón al
16 # estado inactivo
17 if not self.have_selection:
18 widget.set_active(gtk.FALSE)
19 else:
20 if self.have_selection:
21 # No es posible "liberar" la selección en PyGTK
22 # simplemente se señala que no se posee
23 self.have_selection = gtk.FALSE
24 return
25
26 # Llamada cuando otra aplicación reclama la selección
27 def selection_clear(self, widget, event):
28 self.have_selection = gtk.FALSE
29 widget.set_active(gtk.FALSE)
30 return gtk.TRUE
31
32 # Proporciona la hora actual como selección
33 def selection_handle(self, widget, selection_data, info, time_stamp):
34 current_time = time.time()
35 timestr = time.asctime(time.localtime(current_time))
36
37 # Al devolver una cadena única no debe terminar en valor nulo
38 # Esto se hace automáticamente
39 selection_data.set_text(timestr, len(timestr))
40 return
41
42 def __init__(self):
43 self.have_selection = gtk.FALSE
44 # Creamos la ventana principal
45 window = gtk.Window(gtk.WINDOW_TOPLEVEL)
46 window.set_title("Set Selection")
47 window.set_border_width(10)
48 window.connect("destroy", lambda w: gtk.main_quit())
49 self.window = window
50 # Creamos una caja de eventos que contenga el botón, ya que no tiene su
51 # propia gtk.gdk.Window
52 eventbox = gtk.EventBox()
53 eventbox.show()
54 window.add(eventbox)
55
56 # Creamos un botón biestado que actúe como selección
57 selection_button = gtk.ToggleButton("Claim Selection")
58 eventbox.add(selection_button)
59
60 selection_button.connect("toggled", self.selection_toggled, eventbox)
61 eventbox.connect_object("selection_clear_event", self.selection_clear,
62 selection_button)
63
64 eventbox.selection_add_target("PRIMARY", "STRING", 1)
65 eventbox.selection_add_target("PRIMARY", "COMPOUND_TEXT", 1)
66 eventbox.connect("selection_get", self.selection_handle)
67 selection_button.show()
68 window.show()
69
70 def main():
71 gtk.main()
72 return 0
73
74 if __name__ == "__main__":
75 SetSelectionExample()
76 main()