Alimenter la sélection est un peu plus compliqué. Il faut enregistrer des gestionnaires que l'on appelera lorsque la sélection sera réclamée. Pour chaque paire de sélection/cible à gérer, on fait un appel à :
widget.selection_add_target(selection
,target
,info
)
... où les paramètres widget
,
selection
et target
identifient les requêtes dont doit s'occuper ce gestionnaire. Quand une
demande pour une sélection est reçue, on appellera le signal "selection_get".
Le paramètre info
est un nombre entier qui peut être
utilisé comme un identifiant pour la cible spécifique dans le rappel.
La fonction de rappel a la forme :
def selection_get(widget, selection_data, info, time):
Le gtk.SelectionData
est le même que précédemment,
mais cette fois-ci, on est chargé de remplir les champs type
,
format
et data
. Le paramètre
format
est important ici - le serveur X l'utilise
pour savoir si data
nécessite un changement de
l'ordre de ses bytes ou non. Habituellement la valeur est 8, c'est à dire
un caractère, ou 32 pour un entier). Ceci est réalisé en appelant la
méthode :
selection_data.set(type
,format
,data
)
Cette méthode PyGTK peut seulement manipuler des chaînes de caractères
donc le paramètre data
doit être inclus dans une chaîne
Python, mais le format
sera de la dimension
appropriée (par ex. 32 pour les atomes et les nombres entiers, 8 pour les
chaînes). Les modules Python struct
ou StringIO
peuvent être utilisés pour convertir des données non-chaîne en chaîne de caractères.
Par exemple, vous pouvez convertir une liste de nombres entiers vers une chaîne
et renseigner le selection_data
par :
ilist = [1, 2, 3, 4, 5] data = apply(struct.pack, ['%di'%len(ilist)] + ilist) selection_data.set("INTEGER", 32, data)
La méthode suivante établit les données de la sélection à partir de la chaîne indiquée :
selection_data.set_text(str
,len
)
À la demande de l'utilisateur, on réclame la propriété de la sélection en appelant :
result = widget.selection_owner_set(selection
,time
=0L)
... où result
vaut TRUE
si le programme a réclamé la sélection selection
avec succès. Si une autre application réclame la possession
de la sélection, on obtiendra une réponse "selection_clear_event".
Comme exemple de fourniture de sélection, le programme
setselection.py
ajoute une fonction de sélection à un bouton interrupteur compris dans
une boîte gtk.EventBox
. Le
gtk.Eventbox
est nécessaire car la sélection doit
être associée à une gtk.gdk.Window
alors que le
gtk.Button
est un widget "sans fenêtre" dans GTK+ 2.0.
Quand le bouton interrupteur est enfoncé, le programme réclame la propriété
de la sélection primaire. La seule cible reconnue (à part certaines cibles
comme "TARGETS" fournies par GTK+ lui-même) est la cible "STRING". Lorsque
cette cible est demandée, une représentation en chaîne de caractères du temps
actuel est renvoyée. La Figure 21.2, « Exemple de création de sélection » montre le programme
au moment où il prend possession de la sélection primaire.
Voici le code du programme setselection.py :
1 #!/usr/bin/env python 2 # -*- coding:utf-8 -*- 3 # exemple setselection.py 4 5 import pygtk 6 pygtk.require('2.0') 7 import gtk 8 import time 9 10 class SetSelectionExample: 11 # Fonction de rappel quand l'utilisateur modifie la sélection. 12 def selection_toggled(self, widget, window): 13 if widget.get_active(): 14 self.have_selection = window.selection_owner_set("PRIMARY") 15 # si réclamer la sélection échoue, on remet le bouton 16 # dans l'état inactif. 17 if not self.have_selection: 18 widget.set_active(False) 19 else: 20 if self.have_selection: 21 # Impossible de libérer la sélection en PyGTK, 22 # on indique juste que l'on ne la possède pas. 23 self.have_selection = False 24 return 25 26 # Appelé lorsqu'une autre application réclame la sélection. 27 def selection_clear(self, widget, event): 28 self.have_selection = False 29 widget.set_active(False) 30 return True 31 32 # Fournit le temps actuel comme sélection. 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 # Quand on renvoie une chaîne unique, elle ne doit se terminer 38 # par une valeur nulle. Ceci le fait pour nous. 39 selection_data.set_text(timestr, len(timestr)) 40 return 41 42 def __init__(self): 43 self.have_selection = False 44 # Création de la fenêtre de niveau supérieur 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 # Création d'une boîte évènement pour contenir le bouton 51 # car il n'a pas sa propre GdkWindow. 52 eventbox = gtk.EventBox() 53 eventbox.show() 54 window.add(eventbox) 55 56 # Création d'un bouton interrupteur pour agir avec la sélection 57 selection_button = gtk.ToggleButton("Réclamer sélection") 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()