|
Une remarque pertinente ? Une critique impertinente ? Un lynchage en règle ? Une invitation sous les tropiques ? ![]() Ecrivez-moi ! |
![]() |
||||
|
Conçu et enseigné tel qu'en lui même, avec pertes, fracas et
humour de qualité supérieure par Christophe Darmangeat dans le M2 PISE du Master SSAMECI (Université Paris 7) |
|||||
|
Partie 8
Événements insolites
Il est temps à présent d'examiner plus en détail les
différents événements que nous permet de gérer VB. Car il faut bien
l'avouer, jusqu'ici, à part des clics, des clics et encore des clics, on
n'a pas vu grand chose. Et ce serait
bien dommage
de
s'en
tenir là.
1. La notion de Focus
En parlant du Focus, ne pas oublier de prononcer le "s" final, sans quoi
cela risque de prêter à confusion.
A part ça, le focus, dans une application Windows, désigne
le curseur, au sens le plus général du terme. C'est lorsqu'un contrôle
possède le "focus" qu'il devient concerné par la frappe
d'une touche au clavier (la touche Entrée produisant
l'enfoncement d'un bouton, par exemple). Selon les contrôles,
le focus se matérialise à l'écran par un curseur clignotant (dans
une Textbox), ou par un liseré sombre (sur
un Button).
Du point de vue de l'utilisateur, il y a deux moyens
de déplacer le focus
:
L'ordre de passage du focus est régi par la propriété TabIndex de
chaque contrôle : le contrôle qui reçoit le focus par défaut, au lancement
de la Form, est celui dont le TabIndex vaut zéro.
Il va de soi que VB veille à
ce que deux contrôles de la même Form ne puissent jamais posséder la même valeur de
TabIndex (il empêche automatiquement qu'il y ait
des doublons, ou des trous dans la numérotation).
Voyons maintenant le point de vue du programmeur. On peut tout aussi bien
placer d'autorité le focus sur un contrôle par du code, en lui appliquant la
méthode... Focus. Celle-ci peut s'employer pour presque tous les
contrôles... excepté pour ceux qui ne peuvent recevoir le focus. Étonnant,
non ?
Mais le code permet également de détecter l'arrivée du focus sur un
contrôle, ou son départ. Il suffit pour cela de gérer respectivement les
événements Gotfocus et Lostfocus, eux aussi disponibles pour la quasi-totalité
des contrôles.
2. Les événements clavier
Dans un certain nombre d'applications, on peut souhaiter
attribuer certaines conséquences à la frappe de certaines touches
du clavier.
Par exemple, la touche F1 doit ouvrir le fichier d'aide. Autre exemple,
vous pilotez en temps réel les
mouvement
de Zorglub, le grandiose vaisseau de l'hyperespace, grâce aux touches de direction.
Tout cela suppose que la frappe de telle ou telle touche du clavier soit
interprétée par le logiciel comme un événement. Aucun problème, Billou
s'occupe de nous, et pour ce faire nous offre trois événements, pas un de
moins.
Cela signifie que les touches ne produisant pas de caractères, telles les touches de fonction, ou les touches de direction, ne génèrent pas l'événement Keypress, mais génèrent les événements KeyDown et KeyUp Revenons-en à présent à un aspect sur lequel, jusqu'à maintenant, nous ne nous sommes pas
arrêtés autant qu'il le mérite : je veux parler des
paramètres en entrée des procédures événementielles.
Pour ce qui est des généralités sur les paramètres en entrée d'une procédure, je ne vous
ferai pas l'affront de vous réexpliquer ce dont il s'agit. Vous êtes blindés
en algo, et je sais que jamais vous ne vous seriez lancé dans
ce cours sans être des cadors sur la question. Passons donc
rapidement, comme il sied de le faire en présence d'experts.
Dans une procédure événementielle, nous avons toujours pu constater, quel
que soit l'événement, que VB organisait le passage de deux paramètres : le
fameux Sender, et le mystérieux e.
Fameux, le Sender, puisqu'on a déjà vu qu'il s'agissait d'une
variable faisant référence à l'objet qui a déclenché la procédure. Ceci s'est avéré
particulièrement utile lorsque plusieurs objets étaient branchés (par
exemple en cas de clic) sur la même procédure : le paramètre
Sender nous
a alors permis, au sein de cette procédure, d'identifier lequel des contrôles
avait déclenché la procédure, et d'avoir accès à ses propriétés.
Le paramètre e est également une variable qui désigne un objet. Mais cet
objet n'est pas le contrôle qui a déclenché la procédure (évidemment,
puisque c'est Sender, on ne va pas mettre deux fois la même information
sous deux noms différents, eh, patate). D'ailleurs, le paramètre objet e n'est pas
un contrôle du tout. Il représente, si l'on veut, les conditions, ou
les résultats, comme on préfère, de l'événement lui-même. La nature de ses
propriétés variera donc d'un événement à l'autre.
S'il s'agit d'un événement Click,
disons-le tout net, il n'y a pour ainsi dire aucune propriété dans e,
car rien n'est plus tristement banal et sans
caractéristiques particulières qu'un clic. En revanche, s'il s'agit
d'un événement
clavier, c'est tout de suite beaucoup plus intéressant.
Par exemple, lors d'un KeyDown ou d'un KeyUp, e possèdera tout un tas de
propriétés booléennes (Shift, Alt) ou numériques (Keycode) nous permettant
de savoir dans les menus détails quel était l'état du clavier lors du déclenchement
de l'événement.
Lors d'un KeyPress, nous trouvons pour le paramètre en entrée e la
propriété caractère KeyChar, contenant le caractère généré par la touche
pressée.
Ainsi, le code qui afficherait dans une MessageBox une à une les touches
frappées au clavier serait :
Private Sub Button1_KeyPress(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyPressEventArgs)
Handles Button1.KeyPress
Dim tutu As Integer tutu = MsgBox(e.KeyChar, vbOKOnly, "Touche frappée :") End Sub Et voilà le travail, enveloppez, c'est pesé.
Il nous reste toutefois un petit détail à régler avant d'en
avoir définitivement terminé avec les événements clavier. Imaginons que
nous voulions réaliser un "appel à l'aide" avec la touche F1.
Pas le choix, nous devrons passer par un KeyDown (car
la touche F1 n'engendrant aucun caractère, elle ne produit donc pas d'événement Keypress).
Mais là où ça coince, c'est quand on
réfléchit à quel contrôle nous devrons affecter l'événement. En effet, le
focus étant supposé pouvoir se trouver sur bien des endroits de la Form
lorsqu'on appuiera sur la touche F1, il faudrait en bonne logique créer
une procédure Chmoll.KeyDown pour chacun des contrôles Chmoll susceptibles
de posséder
le focus. On n'est pas rendu.
Heureusement, il y a une autre possibilité : faire en sorte
que la Form court-circuite tous les contrôles qui se trouvent sur elle
en cas de frappe de touche au clavier. Il suffit pour cela de régler sa
propriété KeyPreview (qu'on pourrait traduire
approximativement par "interception du clavier") à
True. On n'a plus alors qu'à écrire une seule procédure, celle qui gère
l'événement KeyDown sur la Form. Et dans cette procédure, à tester
si la touche frappée était bien F1, auquel cas on déclenche l'ouverture
de l'aide. Et hop, comme qui rigole.
3. Événements Souris Bon, dans la vie d'un informaticien, il n'y a pas
que le clavier. Il y a aussi la souris. Et la souris, petit animal
vif et malicieux, ça
peut faire plein de choses. Ça peut survoler un contrôle. Ça peut
se faire appuyer un bouton (ou relâcher un bouton précédemment
appuyé) pendant qu'elle est au-dessus d'un contrôle... Bref, une
souris, c'est capable d'engendrer une foultitude d'événements aussi
intéressants que variés.
Trois de ces événements ne requièrent pas
plus de commentaires que cela :
De ces trois événements, qui effectuent le service
minimum, et qui n'envoient quasiment aucun paramètre à la procédure
qu'ils appellent, il n'y a donc pas grand chose à dire
de plus. En revanche, d'autres événements vont nous permettre,
via les propriétés du
paramètre
e, de récupérer des tas de renseignements utiles.
Ces trois événements génèrent
donc un objet e comportant plusieurs propriétés,
dont les plus intéressantes sont :
A noter qu'un contrôle peut partir à la chasse à la souris, et la "capturer" ! C'est-à-dire qu'il peut capter les événements souris, même s'ils ne se produisent pas au-dessus de lui... Il faut pour cela mettre la propriété Capture du contrôle à True. En-dehors des événements qu'elle est capable
de produire, la souris est également intéressante dans la
mesure où son curseur est un moyen très simple d'informer
l'utilisateur de ce qu'il va pouvoir faire avec les
différentes zones d'une application. Windows, Word, Excel,
entre autres éminents exemples, passent leur temps à triturer le curseur de la souris pour
dire à l'utilisateur que là il peut rétrécir une fenêtre, que
là il peut élargir une colonne, que là il peut sélectionner
toute une ligne, etc.
Savoir manipuler l'apparence du
curseur de la souris est donc une chose qui ne coûte pas cher
en termes de savoir-faire technique, et qui est très payante
pour l'ergonomie d'une application.
Pour commencer, il faut savoir que seul des fichiers de type
cursor (*.cur) ou icone ("*.ico)
peuvent devenir un curseur de souris. Si vous
voulez créer des curseurs personnalisés à partir de l'image de
votre choix, il faudra donc avant toute chose prendre soin de
convertir cette image dans le format adéquat. Une manière
simple de procéder est d'utiliser pour cela l'éditeur
incorporé dans Visual Studio, auquel vous aurez accès via la
commande Projet - Ajouter un nouvel élément - Fichier
curseur.
Au passage, vous noterez que Visual Studio contient en interne un véritable bric-à-brac d'outils graphiques, permettant de créer et modifier non seulement des curseurs, mais aussi des icônes, et des tas d'autres choses encore. Il existe toutefois une série de curseurs prédéfinis (les
curseurs standard de Windows), qui apparaissent sous la forme
de membres statiques de la classe Cursors. Par exemple, le
(trop) célèbre sablier est désigné par Cursors.Waitcursor.
Nous reviendrons plus loin sur ce qu'est un "membre
statique". Mais pour l'instant, contentons-nous de noter que pour modifier l'apparence du curseur au-dessus
d'un contrôle, et le transformer, par exemple, dans le (trop)
célèbre sablier, on peut - en-dehors du fait de modifier la
valeur par défaut de la propriété Cursor de ce contrôle
- taper
le code suivant :
Button1.Cursor = Cursors.WaitCursor
Dans le cas d'un curseur personnalisé existant sous la
forme d'un fichier, on entrera :
Button1.Cursor = New Cursor("MonFichierCurseur.cur")
Lorsqu'on veut modifier un curseur, on n'est pas obligé de modifier le curseur par défaut du contrôle. On peut aussi se contenter de modifier le curseur actuel, à savoir : Current.Cursor Lorsqu'on charge un fichier pour jouer le rôle de curseur, celui-ci peut être de type *.cur ou de type *.ico. Cette dernière possibilité est particulièrement intéressante pour produire des effets du meilleur goût (et donner notamment l'illusion qu'on déplace des images alors qu'on ne déplace que le curseur...) 3. Gérer le Glisser - Déposer (Drag & Drop) Un des trucs balaises dans l'interface graphique
de Windows, c'est
qu'on peut se servir de sa souris pour prendre des trucs à un
endroit, les trimballer et aller les mettre ailleurs. La quasi-totalité
des logiciels exploitent cette possibilité, et il serait quand
bien même bien dommage que nous n'apprenions pas à programmer
avec VB ce qu'on appelle en français le "Glisser - Déposer",
et en anglais le "Drag and Drop". N'est-il pas ?
Cela dit, mieux vaut le savoir, mettre en oeuvre le Drag and
Drop, cela suppose une fieffée dose de patience et de rigueur,
car le moins qu'on puisse dire, c'est que ça ne glisse pas comme
sur des roulettes et qu'à la fin, c'est souvent les armes qu'on
dépose. Mais bon, en y allant le plus rationnellement
et le plus méthodiquement possible, on peut espérer s'en sortir vivants.
3.1 Approche générale La première chose à comprendre,
c'est qu'un Drag and Drop est constitué de trois événements
obligatoires, séparés par une quantité
variable d'événements facultatifs. Ces trois
événements incontournables se situent au point de départ
et au point d'arrivée de la
manip :
Aux trois tâches à accomplir, correspondent donc très logiquement
trois événements à gérer. Ce qu'il y a d'hilarant dans
l'affaire, c'est que ces trois événements ne
correspondent pas aux trois tâches en question ! Un
événement (MouseDown) s'occupe de deux des tâches,
alors que la troisième tâche (la gestion du Drop)
mobilise à elle seule deux événements (DragEnter et
DragDrop).
3.2 Les trois événements cruciaux Résumons-nous, en prenant pour le moment un exemple simple : on
va autoriser l'utilisateur à prendre le texte d'un Label (que nous
appellerons Etiquette) pour le poser dans une TextBox (que nous
appellerons Arthur, parce que c'est un joli nom, et que si on l'appelait Perceval,
ça risquerait de nous porter la poisse.
Première étape : Nous devons autoriser Etiquette à être l'objet d'un Drag,
et Arthur à être la cible d'un Drop. Pour le Drag, la méthode
DoDragDrop devra préciser deux paramètres :
Nous entrerons donc, dans la procédure Etiquette.MouseDown
:
Arthur.AllowDrop = True
Etiquette.DoDragDrop(Etiquette.Text, DragDropEffects.All) Deuxième étape : Nous devons gérer à présent l'entrée du curseur (après un Drag)
dans la zone de Drop, c'est-à-dire au-dessus du contrôle Arthur.
C'est là, dans cette procédure Arthur.DragEnter, que nous devrons
préciser l'effet qui devra se produire lors du Drop. A noter que
cette procédure, et cette instruction, sont indispensables, quand
bien même on aura déjà précisé les possibilités lors du MouseDown.
Si l'on veut, lors du MouseDown, on n'a fait que définir ce qui
serait possible. Là, il faut dire ce qui va vraiment se passer.
Cela se fait en affectant la propriété
Effects de l'objet e, via
une énumération :
e.Effects = DragDropEffects.All
Troisième étape : Il ne nous reste plus qu'à préciser, dans la procédure
Arthur.DragDrop,
ce qui doit se passer lors du largage. Ici, c'est très simple :
Arthur doit prendre le texte qui se trouvait dans Etiquette. Si nous
avions été sûrs que seul Etiquette avait pu être victime d'un Drag,
l'affaire auraiot été un peu plus simple. Mais nous avons choisi de
traiter le cas général, celui où l'information a été passée lors
du MouseDown à la propriété Data de l'objet e.
Récupérer les données trimballées dans la
propriété Data de e n'est pas une mince
affaire. On ne peut consulter cette propriété qu'en lui appliquant la méthode GetData,
méthode exigeant elle-même qu'on précise le format des données à
récupérer... données qui doivent être ensuite converties dans le
format approprié par la méthode adéquate ! Bref, la simplicité même,
dans la plus pure tradition Petitmou.
Dans notre exemple, cela donne :
Arthur.Text = e.Data.GetData(DataFormats.Text).ToString
Eh oui, quand même, ça calme, hein. Et là, c'est
un des exemples les
plus simples qu'on puisse imaginer. C'est tout dire.
3.3 Raffinements divers Ce que nous venons de voir, c'est la
base minimale, sans laquelle aucun Drag & Drop n'est possible.
Mais on peut tout à fait enrichir l'interface, en tripatouillant
la tête du curseur de la souris, en affichant ça ou là des
informations, etc. Je me contente ici d'indiquer quelques pistes,
tant le sujet est vaste.
Pour commencer, jetons un oeil rapide sur les autres événements
qu'il est possible de gérer lors d'un Drag & Drop.
Ensuite, j'ai parlé du curseur de la souris : il est en effet
bon de savoir qu'en cas de besoin, on peut par exemple procéder à
une gestion "fine" des coordonnées de la souris durant un Drag &
Drop. En effet, chaque événement où la souris est impliquée - et
lors d'un Drag & Drop, ils le sont tous ! - envoie au paramètre e
deux propriétés, X et Y,
qui précisent les coordonnées de la
souris au moment du déclenchement de l'événement.
Attention toutefois ! Selon
le type d'événement concerné, ces coordonnées
e.X et e.Y
sont stipulées
par rapport au contrôle qui reçoit l'événement, ou par rapport à
l'écran !!! Autant vous dire qu'il ne va pas falloir
s'étonner de certains résultats surréalistes... Dans ce cas, la
démarche sera toujours la même : vérifier dans l'aide, et
effectuer les conversions de coordonnées nécessaires, comme on aura bientôt
l'occasion de le faire dans de croustillants exercices.
La souris communique d'autres informations à l'événement
e, par
exemple l'état de ses boutons - ce qui permet de différencier un
clic gauche d'un clic droit.
Enfin, notre bonheur ne serait pas complet si j'omettais de
signaler que certains contrôles posent des problèmes particuliers
pour le Drag & Drop - et disposent donc de solutions
particulières. Il s'agit en particulier des
ListBox, Combobox et
autres Treeview, qui permettent de Glisser - Déposer un de leurs
éléments, en allant le positionner à un endroit précis. Mais là,
mon courage pourtant légendaire m'abandonne, et je renvoie les
programmeurs concernés à des exemples de code traînant dans les
bouquins ou sur le Net.
Bon, assez discuté, je sens que vous trépignez d'impatience à
l'idée de mettre tout cela en pratique.
L'exercice Lapins est une introduction au Drag & Drop, qui ne pose
aucune difficulté particulière.
Just a pawn in their game, en revanche, est nettement plus... stimulant. Tout d'abord, il faudra absolument décompresser les deux fichiers *.ico livrés avec l'exécutable dans le même répertoire que celui-ci. Cette solution est certes inélégante, mais nous n'apprendrons que plus tard à procéder de la bonne façon. Ensuite, le programme pose quelques petites difficultés, en premier lieu parvenir à susciter l'illusion que l'on promène les pions. Cela vous rappelle-t-il une remarque faite un peu plus haut ? |
||||