Programmation événementielle et composants d’interface (« widgets »)
Logiciel traditionnel,sans interface utilisateur
{
Lire les entrées d’un fichier
Effectuer des calculs
Écrire les sorties dans un fichier
}
… avec interface utilisateur minimale
{
Lire les entrées du clavier
Effectuer des calculs
Écrire les sorties sur l’écran
}
… dans une boucleRépéter {
Afficher l’invite de commandes
Lire la commande
Exécuter la commande
Écrire les sorties sur l’écran
}
Logiciel événementiel(« event-driven program»)
Répéter {
Attendre un événement
Traiter l’événement
}
Logiciel événementielpour une interface graphique
Afficher l’interface (fenêtre(s), etc.)Répéter { Attendre un événement d’entrée e switch(e.type) { case KEY_PRESS: ... case MOUSE_BUTTON: ... case MOUSE_MOTION: ... } Si nécessaire, mettre à jour l’affichage}
Boucle d’événements
Logiciel traditionnel:• Le logiciel « a le contrôle ».• Le logiciel peut prendre le temps nécessaire pour
traiter les entrées. L’utilisateur doit attendre.• Les entrées sont limitées
aux chaînes de caractères.Logiciel graphique interactif:• L’utilisateur doit (avoir l’impression de)
« avoir le contrôle ».• Le logiciel doit traiter chaque événement assez
rapidement pour répondre en temps réel.• L’utilisateur peut générer différents événements
à tout moment.
Structure, ou classe, d’événement
Event {
unsigned long int timestamp;
int type; // KEY_PRESS, MOUSE_...
int x, y;
int key;
boolean flag...
...
}
Sortes d’événements (1)
• KEY_DOWN ou …_PRESS (touche appuyée),KEY_UP ou …_RELEASE (touche relâchée),KEY_TYPED (synonyme pour DOWN + UP)– Attributs:
temps,caractère ASCII (‘a’, ‘b’, ‘c’, …),touche de clavier (F1, F2, PageUp, Esc, …),s’il s’agit d’une auto-répétition ou non,coordonnées (x, y) de la souris,état des touches de modification (Ctrl, Shift, etc.)
Sortes d’événements (2)• MOUSE_DOWN ou …_PRESS (bouton appuyé),
MOUSE_UP ou …_RELEASE (bouton relâché),MOUSE_CLICK (synonyme pour DOWN + UP)MOUSE_DOUBLE_CLICK,MOUSE_MOTION ou …_MOVEMENT (mouvement),MOUSE_DRAG (glissement)
– Attributs: temps,bouton (1-5) (gauche, droit, milieu, …),coordonnées (x, y),état de tous les boutons (utile pour les combinaisons),état des touches de modification (Ctrl, Shift, etc.)
– Taux d’échantillonnage de la position dépend habituellement de la charge CPU
Autres sortes d’événements?
Autres sortes d’événements?
Sortes d’événements (3)
• RESIZE (redimensionnement),MAXIMIZE, MINIMIZE– Attributs: temps,
nouvelles dimensions (width, height)
• WINDOW_CLOSE– Permet au logiciel de sauvegarder ses données,
faire le ménage, etc.
Autres sortes d’événements?
Sortes d’événements (4)
• MOUSE_ENTER (souris entre dans la fenêtre),MOUSE_LEAVE ou …_EXIT (souris sort de la fenêtre)
– Attributs: semblable à ceux des autres événements de souris
• REDRAW ou EXPOSE ou PAINT (demande de redessiner)
– Peut être généré par un redimensionnement,un mouvement d’une autre fenêtre,ou par une demande du client même
– Attributs:rectangle(s) à redessiner (x, y, width, height),c.-à-d. les rectangles endommagés (« damaged »)
Rectangles endommagés
Boucle d’événementsen C avec Xlib (UNIX/X11)
XEvent event;
ouvrir une fenêtre
while (!quit) {
XNextEvent(..., &event); // attend le prochain événement
switch (event.type) {
case Expose: ... // redessiner
case ConfigureNotify: ... // redimensionnement
case ButtonPress: ... // bouton de souris
case ButtonRelease: ... // bouton de souris
case MotionNotify: ... // mouvement de souris
case KeyPress: // touche de clavier
switch (XLookupKeysym(&event.xkey, ...)) {
case XK_F1: ... // afficher de l’aide
case XK_Escape: quit=true; break;
}
break;
}
}
Boucle d’événements Xlib – comment travailler en même tempswhile (!quit) {
while (0 == XEventsQueued(...)) {
// Peut avancer une animation, simulation, des calculs, etc.
faireUnPeuDeTravail();
usleep(100000); // dormir une fraction de seconde
}
XNextEvent(..., &event);
switch (event.type) {
case ...
}
}
Optionnel
Une autre façon de faire du travaille en même temps:utiliser des événements spéciaux …
Sortes d’événements (5)
• TIMER ou TIMEOUT (un délai de temps expiré),IDLE (le CPU est libre)– Envoyés au client sur demande seulement– Permettent de faire un peu de travail en attendant
d’autres événements– Les « timeouts » peuvent être envoyés de façon
périodique (exemple: pour une animation),ou seulement une fois (ex: pour retarder une action)
Exemples d’actions retardées
Affichage d’une infobulle Ouverture d’un sous-menu
Traitement d’événementsen C avec GLUT (OpenGL)
void drawHandler() {
... // redessiner
}
void reshapeHandler( int width, int height ) {
... // redimensionnement
}
void mouseHandler( int button,int state,int x,int y ) {
// boutons de souris
if (button==GLUT_LEFT_BUTTON && state==GLUT_DOWN) ...
}
void passiveMotionHandler( int x, int y ) {
... // mouvement de souris
}
void motionHandler( int x, int y ) {
... // glissement de souris
}
void keyboardHandler( unsigned char key, int x, int y ) {
... // touches normales
}
void specialKeyHandler( int key, int x, int y ) {
... // touches spéciales
}
int main( ... ) {
glutInit...
glutCreateWindow( "My Window" );
glutDisplayFunc( drawHandler );
glutReshapeFunc( reshapeHandler );
glutMouseFunc( mouseHandler );
...
glutMainLoop();
}
• Ces sous-routines s’appellent des « event handlers » (traiteurs d’événements)ou « callbacks »
• Où est la boucle d’événements?
Classes d’événements,architecture orientée objets
Event
KeyEventMouseEvent
MouseButtonEvent MouseMotionEvent
…
…
• Les informations décrivant les événements peuvent être encodées dans une structure (exemple: Xlib), une ou plusieurs classes (ex: Java), ou de simples paramètres (ex: GLUT).
• Ces informations peuvent être traitées par une seule sous-routine, ou par plusieurs sous-routines selon le type d’événement. (Ces sous-routines s’appellent « event handlers » (traiteurs d’événements), ou « callbacks », ou sont des méthodes d’objets « event listeners » (écouters d’événements))
• La boucle d’événements peut être située dans le code du client (ex: Xlib), ou à l’extérieur (dans une librarie ou « framework »; ex: GLUT).
Quelques exemples en Java …
Quelques éléments desinterfaces graphiques
Les fenêtres
Les fenêtres
Curseurs standards de X11
Les curseurs de souris (ou pointeurs)
Curseur de souris, ou pointeur
« hotspot »
Les curseurs de texte (« caret »)
Les widgets
Les boutons
Les boutons
Les boutons
Les cases à cocher (« checkbox »)
Pour des choix binaires et indépendants
Les boutons radio
Pour des choix mutuellement exclusifs
Les infobulles (« tooltips »)
Barre de défilementou glisseur
(« scrollbar » ou « slider »)
Défileur (« thumb » ou « slider »)
Barre de défilementcontextuelle (« popup slider »)
Barre de progrès
Les champs
• Champs de texte• Champs numériques
– Avec « spinner »– Avec unités– Avec barre de défilement
Les menus
item ou commande (« menu item »)
Barre de menus
Menu déroulant (« Pull-down menu »)
Menu contextuel(« popup menu » ou « context-sensitive menu »)
C’est quoi la différence entre « popup » et « context-sensitive » ?
Les menus d’options(« option menus »)
Affichage de sous-menus
Les ellipses …
Menus détachés ou menus flottants (« Tear-off menus »)
Liste déroulante(« Pick list » ou « Scrolling list »)
Menu divisé (« Split menu »)
Menu divisé (« Split menu »)
Les cadres
Les onglets
Les onglets
Des onglets hiérarchiques ?
Les séparateurs
Un bouton + menu
Créateur de tables
Les palettes de boutons
Les barres d’outils
Des boîtes de dialogue
2 sortes de boîtes de dialogue
• Modale (« modal »)– Oblige l’utilisateur de compléter son interaction
avec la boîte avant de retourner à la fenêtre principale
• Non-modale (« modeless »)– Plusieurs boîtes non-modales peuvent être
ouvertes en même temps dans une même application
Les tableaux
« tree list »
« tree list »
Cadres défilables (« scrolling area »)
Sélecteur de couleur (« color picker »)
Sélecteur de couleur (« color picker »)
Observations
• Widgets simples vs widgets composés• Widgets composés:
– Un enfant vs plusieurs enfants
– Contenu fixe vs contenu variable
Observations (2)Certains widgets aident à gérer l’espace• Onglets, menus, barres de défilement, …
L’exemple de SimpleDraw.java …
class Stroke ArrayList< Point2D > points = …; AlignedRectangle2D getBoundingRectangle() draw()class Drawing ArrayList< Stroke > strokes = …; AlignedRectangle2D getBoundingRectangle() draw()class MyCanvas RadialMenuWidget radialMenu = …; paintComponent() mousePressed() mouseReleased() mouseMoved() mouseDragged()class SimpleDraw actionPerformed() createUI() main()
class CustomWidget pressEvent() releaseEvent() moveEvent() dragEvent() draw()
class RadialMenuWidget …
RadialMenuWidget.java
SimpleDraw.javaCustomWidget.java
JMenuBar menuBar
JMenu("File")
JMenu("View")
JMenu("Help")
JMenuItem("Clear")
JMenuItem(“Quit")
JFrame frame
Container toolPanel MyCanvas canvas
JRadioButton(…)
JButton("Delete Selection")
JButton("Frame Selection")
… …
RadialMenuWidget
Top Related