Cours 2a : Programmation des interfaces graphiques

publicité
Cours 2a :
Programmation des
interfaces graphiques
[email protected]
(partie de la présentation basée sur des transparents d’Anastasia Bezerianos,
Fanis Tsandilas et Michel Beaudouin-Lafon)
Interfaces graphiques (GUIs)
l'interaction graphique : les entrées sont spécifiées
directement à partir des sorties.
Le périphérique d’entrée spécifie une commande de
position à l'écran qui désigne un objet
précédemment affiché par le système (pointage).
Elle est familière dans le monde physique.
Interfaces WIMP
WIMP : Window, Icons, Menus and Pointing
Fenêtres, Icones, menus et pointage.
Présentation
Fenêtre, icones et autres objets graphiques
Interaction
Menus, boites de dialogue, texte
Entrée
pointage, sélection, tracé
Boucle action perception
Feedback
Couches logicielles
Squelette d’application
MacApp
Java Swing, Qt, GTK+, MFC, Cocoa
X Windows
GDI+, Quartz, GTK+/Xlib, OpenGL
Windows, Mac OS X, Linux
Dispositifs d’entrée/sortie
Entrée : Saisir des commandes et des données
Sortie : le système affiche de l’information et montre son état
Interactivité vs. Algorithmique
système algorithmique (fermés) :
–  lit des entrées, calcule, produit un
résultat
–  il y a un état final
système interactif (ouverts) :
–  évènements provenant de l’extérieur
–  boucle infinie, non déterministe
Problème
vous avez appris à programmer des algorithmes
(la partie “calcul”)
la plupart des langages de programmation (C, C
++, Java, Lisp, Scheme, Ada, Pascal, Fortran,
Cobol, ...) sont conçus pour écrire des
algorithmes, pas des systèmes interactifs
Problème
Traitement des entrées/sorties pendant le calcul
–  Instructions de sortie (print, put, send,…)
pour envoyer des données aux périphériques
–  Instructions de lecture (read, get, receive,
…) pour lire l’état ou changement d’états de
périphériques d’entrée, du façon bloquante
Problème
obligés d’écrire des SI sous une forme
algorithmique :
Comment gérer les entrées
- 1 pér. à la fois
-  Attente active
-  état des plusieurs pér.
- CPU
Programmation évènementielle
File d’attente (queue)
queue.enqueue(event)
while active
if queue is not empty
event <- queue.dequeue()
source <- findSource(event)
source.processEvent(event)
end if
end while
Programmation évènementielle
Source :
Mouse Click
File d’attente (queue)
queue.enqueue(event)
Cible :
Bouton « Cancel »
while active
if queue is not empty
event <- queue.dequeue()
source <- findSource(event)
source.processEvent(event)
end if
end while
processEvent(event)
target <- FindTarget (event)
if (target ≠ NULL)
target.processEvent(event)
Exemple : Swing (AWT)
3 processus
•  Initial : main()
•  EDT gères la liste d’évènements :
envoie les évènements aux
listeners et appel la méthode paint
•  Tache de fond : exécute les actions
plus longues
Boîte à outils d’interface
Bibliothèques d’objets interactifs (les « widgets »)
que l’on assemble pour construire l’interface
Fonctionnalités pour faciliter la programmation
d’applications graphiques interactives
Boîte à outils d’interface
Pourquoi Java Swing
Java (toutes plateformes et beaucoup de librairies)
Beaucoup de ressources en ligne
Pourquoi Java Swing
Java (toutes plateformes et beaucoup de librairies)
Beaucoup de ressources en ligne
Alternatives
•  JavaFX : s’impose petit à petit pour les interfaces
en Java car permet de travailler avec beaucoup
de matériel différent.
les « widgets »
bouton
menu
fenêtre
barre d’outils
onglet
étiquette
zone de texte
bouton radio
liste
barre de
défilement
« slider »
les widgets de Swing
les widgets de Swing
Complexité des widgets
widgets « simples »
buttons, barres de défilement, …
widgets « composés »
Destinés à contenir d’autres widgets (simples ou
composés)
Boites de dialogue, menus, …
Hiérarchie des widgets
–  un composant ne peut appartenir qu’à un seul « container »
Racine (composé)
correspond à une
fenêtre de l’appli
Nœuds (composé)
Structure visuel ou
fonctionnel du contenu
Feuille (simple)
avec lesquels l’utilisateur
peut interagir
Classes des widgets SWING
Une application graphique à un containeur principal qui contient tous les
autres.
3 types différents dans SWING : Jframe, Jdialog et Japplet
Ils contiennent tous des widgets qui sont contenus dans le content pane
JFrame
Public static void main (String[] args) {
JFrame frame = new JFrame (Ma première fenêtre);
frame.setVisible(true);
}
Dialog
Public static void main (String[] args) {
JFrame frame = new JFrame (« Ma première fenêtre »);
frame.setVisible(true);
JDialog dialog = new JDialog (frame, « Hello world », true);
}
Modale
Exercice
Identifier les widgets de cette interface
Facettes des widgets
les « widgets »
bouton
menu
fenêtre
barre d’outils
onglet
étiquette
zone de texte
bouton radio
liste
barre de
défilement
« slider »
Facettes des widgets
Présentation
apparence graphique
Comportement
réactions aux actions de l’utilisateur
Interfaçage avec l’application :
notifications de changement d’état
Facettes des widgets
Exemple : Bouton
Présentation
cadre avec un nom à l’intérieur
Comportement
« enfoncement » ou « relâchement » lorsque l’on clique dessus
Interfaçage avec l’application :
fonction appelée lorsque le bouton est cliqué
Facettes des widgets
Exemple : Slider
Présentation
?
Comportement
?
Interfaçage avec l’application :
?
Facettes d’un widget
Notifications de changement d’état :
–  variables actives (Tcl/Tk)
–  envoi d’évènements(Qt)
–  fonctions de rappel (« callbacks »)
Variables actives
lien bidirectionnel entre une variable d’état du widget
et une variable de l’application
problèmes
–  limité aux types simples
–  lien de retour peut être coûteux
–  Erreurs si les liens sont mis à jour par des développeurs
Envoi d’évènements
Les widgets agissent comme des périphériques
d’entrée et envoient des évènements.
Une boucle tant que lit et traite les évènements
Association d’un objet à un widget et de
méthodes de l’objet aux changements d’état
Envoi d’évènements
Sépare l’envoi et le traitement des évènements
Meilleure encapsulation
Fonctions de rappel
Enregistrement lors de la création du widget
Appel lors l’activation du widget
Fonctions de rappel
Problème : spaghetti des callbacks
Partage d’état entre plusieurs callbacks par :
–  variables globales
•  Trop dans une application réelle
–  arbre des widgets : la fonction de rappel est appelée en lui passant
le widget qui l’a déclenché
•  Fragile si l’on change la structure, insuffisante pour d’autres données
pas associés aux widgets
–  « jeton » (token) : donnée enregistrée avec la callback, passée
automatiquement au moment de l’appel
fonctions de rappel
/* fonction de rappel */
void DoSave (Widget w, void* data) {
/* récupérer le nom de fichier */
filename = (char**) data;
/* appeler la fonction de l’application */
SaveTo (filename);
/* fermer la boîte de dialogue */
CloseWinfow (getParent(getParent(w)));
}
/* programme principal */
main () {
/* variable contenant le nom du fichier */
char* filename = “”;
…
/* créer le widgets et lui associer sa callback */
ok = CreateButton (....);
RegisterCallback (ok, DoSave, (void*) &filename);
…
/* boucle de traitement des événements */
MainLoop ();
}
« event listeners » (Java)
Variante des callbacks adaptée au Java:
Méthodes de type AddListener spécifient non pas
une fonction de callback, mais un objet (le
listener)
Lorsque le widget change d’état, il déclenche une
méthode prédéfinie du listener (par exemple
actionPerformed)
« event listeners » (Java)
public class ClickListener implements ActionListener {
public void actionPerformed(ActionEvent e){
JButton button = (JButton)e.getSource();
…
}
}
…
ClickListener listener = new ClickListener();
JButton button = new JButton(’’Click me’’);
button.addActionListener(listener);
…
« event listeners » (Java)
Anonymous Inner classes
…
button.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e){
…
}
});
…
panel.addMouseListener(new MouseAdapter(){
public void mouseClicked(MouseEvent e){
…
}
});
Fonctions et évènements prédéfinis
« event listeners » (Java)
Anonymous Inner classes
“new <nom-de-classe> () { <corps> }”
cette construction fait deux choses :
§  elle crée une nouvelle classe, sans nom, qui est
une sous-classe de <nom-de-classe> définie par
<corps>
§  elle crée une instance (unique) de cette nouvelle
classe et retourne sa valeur
Cette class a accès aux variables et méthodes de
la classe dans la quelle elle est définie
Evènements et Ecouteurs
Chaque évènement à une source (Jbutton, JRadioButton, Jmenu,
JTextField) à laquelle on accède via la méthode getSource()
Les listeners doivent implémenter l’interface qui correspond aux
évènements.
Ex : ActionEvent => ActionListener
Evènements et Ecouteurs
Tous les évènements héritent de la classe EventObject
Tous les listeners héritent de EventListener
Quelques couple Events – Listener
•  ActionEvent
ActionListener
•  MouseEvent
MouseListener
•  KeyEvent
KeyListener
•  …
Evènements et Ecouteurs
Les listeners doivent être enregistrés (ajoutés) aux widgets.
Un listener peut être ajouté à plusieurs widgets.
Un listener pour plusieurs boutons par exemple
Un widget peut avoir plusieurs listeners
Un pour le click et un pour la touche entrée sur un bouton
Exercice
Identifier les listeners de cette interface
« drag-and-drop »
Quels sont les « widgets » affectés ?
Quels sont les évènements?
Exercice : comment décrire cette interaction
avec un « event listener » ?
« drag-and-drop »
Quels sont les « widgets » affectés ?
Quels sont les évènements?
Exercice : comment décrire cette interaction
avec un « event listener » ?
http://openclassrooms.com/courses/apprenez-a-programmer-en-java/le-drag-n-drop
Téléchargement