La méthode drag_source_set()
indique un ensemble de types de cibles pour une opération de glisser sur un widget.
widget.drag_source_set(start_button_mask,targets,actions)
Les paramètres ont la signification suivante :
Le paramètre widget indique le
widget origine du glisser
Le paramètre start_button_mask indique
un masque de bits des boutons qui peuvent débuter le glisser
(par ex. BUTTON1_MASK)
Le paramètre targets indique une liste de
types de données cibles gérées par le glisser
Le paramètre actions indique un masque
de bits des actions possibles pour un glisser depuis cette fenêtre
Le paramètre targets est une liste de
tuples semblable à :
(target, flags, info)
... où target est une chaîne de
caractères représentant le type de glisser
... où flags limite la portée du
glisser. Il peut prendre la valeur 0 (pas de limitation de la portée)
ou la valeur des constantes suivantes :
gtk.TARGET_SAME_APP # La destination peut être sélectionnée pour un glisser à l'intérieur de la même application gtk.TARGET_SAME_WIDGET # La destination peut être sélectionnée pour un glisser à l'intérieur du même widget
... où info est un identifiant entier
assigné à l'application.
S'il n'est plus nécessaire qu'un widget continue d'être l'origine
d'une opération de glisser-déposer, la méthode
drag_source_unset()
widget.drag_source_unset()
Les signaux suivants sont envoyés au widget origine pendant une opération de glisser-déposer :
Tableau 22.1. Signaux du widget origine
| drag_begin (début du glisser) | def drag_begin_cb(widget, drag_context, data): |
| drag_data_get (obtention des données du glisser) | def drag_data_get_cb(widget, drag_context, selection_data, info, time, data): |
| drag_data_delete (suppression des données du glisser) | def drag_data_delete_cb(widget, drag_context, data): |
| drag_end (fin du glisser) | def drag_end_cb(widget, drag_context, data): |
Le gestionnaire du signal "drag-begin" peut être utilisé pour
définir des conditions de départ telle que l'icône du glisser en utilisant
une des méthodes suivantes de la classe Widget :
drag_source_set_icon(),
drag_source_set_icon_pixbuf(),
drag_source_set_icon_stock(). Le gestionnaire
du signal "drag-end" peut servir à annuler les actions du gestionnaire
du signal "drag-begin".
Le gestionnaire du signal "drag-data-get" devrait renvoyer les
données de glisser correspondantes à la destination indiquée par le paramètre
info. Il fournit à
gtk.gdk.SelectionData les données du glisser.
Le gestionnaire du signal "drag-delete" est utilisé pour supprimer
les données du glisser d'une action gtk.gdk.ACTION_MOVE
une fois la copie des données effectuée.
La méthode drag_dest_set() indique que
ce widget peut recevoir le déposer et précise les types de déposer qu'il
peut accepter.
La méthode drag_dest_unset() indique que ce
widget ne peut plus maintenant recevoir de déposer.
widget.drag_dest_set(flags,targets,actions) widget.drag_dest_unset()
... où le paramètre flags indique quelles
actions GTK+ doit réaliser pour le widget pour y effectuer le dépot. Voici
les valeurs possibles pour flags :
gtk.DEST_DEFAULT_MOTION |
Si activé pour un widget, GTK+ vérifiera, pendant le survol
d'un glisser au-dessus de ce widget, si le glisser appartient à la liste
des cibles et actions possibles de ce widget. Alors, GTK+ appellera
la méthode |
gtk.DEST_DEFAULT_HIGHLIGHT |
Si activé pour un widget, GTK+ mettra en évidence ce widget pendant la durée du survol par le glisser, si l'action et le format du widget sont compatibles. |
gtk.DEST_DEFAULT_DROP |
Si activé pour un widget, au moment du déposer, GTK+ vérifiera
si le glisser concorde avec la liste des cibles et action possibles
de ce widget ; si oui, GTK+ appellera la méthode
|
gtk.DEST_DEFAULT_ALL |
Si activé, indique que toutes les actions précédentes doivent être rélisées. |
Le paramètre targets est une liste de
tuples d'information de cibles décrites précèdemment.
Le paramètre actions est un masque de bits
des actions possibles à réaliser lors d'un glisser sur ce widget. Les
valeurs possibles, combinables avec l'opérateur OR, sont les suivantes :
gtk.gdk.ACTION_DEFAULT gtk.gdk.ACTION_COPY gtk.gdk.ACTION_MOVE gtk.gdk.ACTION_LINK gtk.gdk.ACTION_PRIVATE gtk.gdk.ACTION_ASK
Les paramètres targets et
actions sont ignorés si le paramètre
flags ne contient pas gtk.DEST_DEFAULT_MOTION
ou gtk.DEST_DEFAULT_DROP. Dans ce cas, l'application
doit gérer les signaux "drag-motion" et "drag-drop".
Le gestionnaire du signal "drag-motion" doit déterminer si les
données du glisser sont appropriées en comparant les cibles de destination
avec les cibles gtk.gdk.DragContext. Il peut aussi
étudier les données du glisser en appelant la méthode
drag_get_data() method. Il faut utiliser la méthode
gtk.gdk.DragContext.drag_status()
pour mettre à jour le statut du paramètre drag_context.
Le gestionnaire du signal "drag-drop" doit déterminer la cible qui
correspond en utilisant la méthode
drag_dest_find_target() du widget et ensuite réclamer
les données du glisser en utilisant la méthode
drag_get_data(). Les données
seront disponibles dans le gestionnaire du signal "drag-data-received".
Le programme
dragtargets.py
affiche les cibles possible d'une opération de glisser dans un widget étiquette.
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 context.finish(True, False, time)
14 return True
15
16 w = gtk.Window()
17 w.set_size_request(200, 150)
18 w.drag_dest_set(0, [], 0)
19 w.connect('drag_motion', motion_cb)
20 w.connect('drag_drop', drop_cb)
21 w.connect('destroy', lambda w: gtk.main_quit())
22 l = gtk.Label()
23 w.add(l)
24 w.show_all()
25
26 gtk.main()
Le programme crée une fenêtre et ensuite l'utilise comme
destination d'un glisser sans cible, ni action en fixant les drapeaux à zéro.
Les gestionnaires motion_cb() et drop_cb()
sont connectés respectivement aux signaux "drag-motion" et "drag-drop".
Le gestionnaire motion_cb() se contente de configurer l'état
du glisser pour permettre un déposer. Le gestionnaire drop_cb()
modifie le texte de l'étiquette pour indiquer les cibles du glisser et termine
le déposer en laissant intacte la source des données.
Pendant une opération de glisser-déposer, les signaux suivants sont transmis au widget destination.
Tableau 22.2. Signaux du widget destination
| drag_motion (mouvement du glisser) | def drag_motion_cb(widget, drag_context, x, y, time, data): |
| drag_drop (glisser-déposer) | def drag_drop_cb(widget, drag_context, x, y, time, data): |
| drag_data_received (données reçues) | def drag_data_received_cb(widget, drag_context, x, y, selection_data, info, time, data): |
Le programme
dragndrop.py
illustre l'utilisation du glisser-déposer dans une application. Un bouton
avec une image
(gtkxpm.py)
constitue la source du glisser, il fournit en même temps un texte et une
donnée xpm. Un widget layout constituera la destination du déposer du xpm,
un bouton, la destination du texte. La Figure 22.1, « Exemple de glisser-déposer »
montre le programme après le déposer du xpm et du texte, respectivement
sur le layout et sur le bouton.
Voici le code de dragndrop.py :
1 #!/usr/bin/env python
2 # -*- coding:utf-8 -*-
3 # exemple 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 ExempleDragNDrop:
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(False,0)
33 box.show()
34 table = gtk.Table(2, 2, False)
35 table.show()
36 box.pack_start(table, True, 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 # créer les barres de défilement et les placer dans une table
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 # utiliser les ajustements du layout par les barres de défilement
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, False, 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 # s'adapter au défilement du layout - la localisation de l'évènement
90 # est relative à la zone visible et non à la taille du layout
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 ExempleDragNDrop()
124 main()