Le cours et les énoncés d'exercices pour la session 2020 est disponible en suivant ce lien. Nous évaluerons votre progression en IHM au moyen de rendus réguliers, qui devront s'opérer sur l'ENT, dans le Moodle du module d'IHM. Pierre Gérard a fait une vidéo pour introduire le cours.
Pour les années avant 2020, le cours et énoncés se trouvaient à l'adresse suivante.
De nombreux exemples de programmation avec SWING sont donnés sur cette page. En ce qui concerne 2D Graphics, vous pouvez vous référer à la page suivante ou encore à cette page.
Concernant le fil conducteur des exercices d'avant 2020 (Station météo), vous pouvez consulter, à titre informatif, l'interface d'accès aux informations météorologiques mondiale sur la page du Système d'Information Météorologique Mondial (WWIS) .
Vous aurez alors les moyens de construire votre propre interface graphique qui propose la météo de toutes les villes du monde. Il faudra être capable d'effectuer une requête (curl ?), puis de parser/analyser un fichier XML. Voici un exemple de requête curl pour la ville de New York :
$ curl http://worldweather.wmo.int/fr/json/278_fr.xml {"city":{"lang":"fr","cityName":"New York City, New York","cityLatitude":"40.650000000","cityLongitude":"-73.780000000","cityId":278,"isCapital":false,"stationName":"New York City, New York","tourismURL":"","tourismBoardName":"","isDep":false,"timeZone":"-0400","isDST":"Y","member":{"memId":93,"memName":"Etats-Unis","shortMemName":"","url":"www.nws.noaa.gov\/","orgName":"National Weather Service","logo":"usa_logo.png","ra":4},"forecast":{"issueDate":"2019-04-17 22:40:00","timeZone":"Local","forecastDay":[{"forecastDate":"2019-04-18","wxdesc":"","weather":"pluie fine","minTemp":"9","maxTemp":"17","minTempF":"48","maxTempF":"63","weatherIcon":1502},{"forecastDate":"2019-04-19","wxdesc":"","weather":"Petite averse","minTemp":"14","maxTemp":"21","minTempF":"57","maxTempF":"69","weatherIcon":1201},{"forecastDate":"2019-04-20","wxdesc":"","weather":"Averse de pluie","minTemp":"16","maxTemp":"19","minTempF":"60","maxTempF":"66","weatherIcon":901},{"forecastDate":"2019-04-21","wxdesc":"","weather":"Petite averse","minTemp":"11","maxTemp":"17","minTempF":"52","maxTempF":"63","weatherIcon":1201},{"forecastDate":"2019-04-22","wxdesc":"","weather":"Ensoleill\u00e9","minTemp":"11","maxTemp":"21","minTempF":"52","maxTempF":"70","weatherIcon":2402},{"forecastDate":"2019-04-23","wxdesc":"","weather":"P\u00e9riode ensoleill\u00e9e","minTemp":"12","maxTemp":"18","minTempF":"54","maxTempF":"65","weatherIcon":2201},{"forecastDate":"2019-04-24","wxdesc":"","weather":"Petite averse","minTemp":"10","maxTemp":"16","minTempF":"50","maxTempF":"61","weatherIcon":1201}]},"climate":{"raintype":"Rainfall","raindef":"","rainunit":"inch","datab":1981,"datae":2010,"tempb":"","tempe":"","rdayb":"","rdaye":"","rainfallb":"","rainfalle":"","climatefromclino":"","climateMonth":[{"month":1,"maxTemp":"3.5","minTemp":"-2.8","meanTemp":null,"maxTempF":"38.3","minTempF":"26.9","meanTempF":null,"raindays":"10.4","rainfall":"92.7","climateFromMemDate":"2014-01-06"},{"month":2,"maxTemp":"5.3","minTemp":"-1.7","meanTemp":null,"maxTempF":"41.6","minTempF":"28.9","meanTempF":null,"raindays":"9.2","rainfall":"78.5","climateFromMemDate":"2014-01-06"},{"month":3,"maxTemp":"9.8","minTemp":"1.8","meanTemp":null,"maxTempF":"49.7","minTempF":"35.2","meanTempF":null,"raindays":"10.9","rainfall":"110.7","climateFromMemDate":"2014-01-06"},{"month":4,"maxTemp":"16.2","minTemp":"7.1","meanTemp":null,"maxTempF":"61.2","minTempF":"44.8","meanTempF":null,"raindays":"11.5","rainfall":"114.3","climateFromMemDate":"2014-01-06"},{"month":5,"maxTemp":"21.6","minTemp":"12.2","meanTemp":null,"maxTempF":"70.8","minTempF":"54.0","meanTempF":null,"raindays":"11.1","rainfall":"106.4","climateFromMemDate":"2014-01-06"},{"month":6,"maxTemp":"26.3","minTemp":"17.6","meanTemp":null,"maxTempF":"79.3","minTempF":"63.6","meanTempF":null,"raindays":"11.2","rainfall":"112.0","climateFromMemDate":"2014-01-06"},{"month":7,"maxTemp":"28.9","minTemp":"20.4","meanTemp":null,"maxTempF":"84.1","minTempF":"68.8","meanTempF":null,"raindays":"10.4","rainfall":"116.8","climateFromMemDate":"2014-01-06"},{"month":8,"maxTemp":"28.1","minTemp":"19.9","meanTemp":null,"maxTempF":"82.6","minTempF":"67.8","meanTempF":null,"raindays":"9.5","rainfall":"112.8","climateFromMemDate":"2014-01-06"},{"month":9,"maxTemp":"24.0","minTemp":"16.0","meanTemp":null,"maxTempF":"75.2","minTempF":"60.8","meanTempF":null,"raindays":"8.7","rainfall":"108.7","climateFromMemDate":"2014-01-06"},{"month":10,"maxTemp":"17.7","minTemp":"10.0","meanTemp":null,"maxTempF":"63.8","minTempF":"50.0","meanTempF":null,"raindays":"8.9","rainfall":"111.8","climateFromMemDate":"2014-01-06"},{"month":11,"maxTemp":"12.1","minTemp":"5.3","meanTemp":null,"maxTempF":"53.8","minTempF":"41.6","meanTempF":null,"raindays":"9.6","rainfall":"102.1","climateFromMemDate":"2014-01-06"},{"month":12,"maxTemp":"6.1","minTemp":"0.0","meanTemp":null,"maxTempF":"43.0","minTempF":"32.0","meanTempF":null,"raindays":"10.6","rainfall":"101.6","climateFromMemDate":"2014-01-06"}]}}}macbook-de-christophe:~ christophecerin$
Tout ce qui suit sur cette page ne sont que des compléments pour découvrir les différents facettes des interfaces graphiques. Voir par exmeple cette présentation introduisant l'histoire et des vieux outils (ncurses, X11, Python Tkinter). Ce polycopié propose également des exercices de programmation. Il y a aussi des éléments introductifs à Swing sur la page suivante à l'IRIF. Une édition du livre Java Swing, 2nd edition chez O'Reilly est à lire avec profit ! Pour une introduction (en anglais) à Programming Graphical User Interface (GUI) in Java, voir ce lien très complet. En français, on pourra préférer la lecture de cette page qui détaille l'ensemble des méthodes qu'un objet graphique peut appeler. J'ai repris plus bas quelques éléments méthodologiques de ce cours, que j'ai commentés.
Je vous conseille d'examiner les codes proposés aux correcteurs sous l'angle MVC (Model View Controler) tel que ce concept est aussi présenté ici ou ici (plus élaboré) ou encore ce post. Il s'agit pour l'étudiant de repérer les parties son code relatives à la View, au Model et au Controler. Attention, certains codes à rendre ne contiennent pas de partie controler (ce sont alors des exemples qui se concentrent sur autre chose). Il est donc important de documenter votre code pour montrer où commence et où termine la partie View par exemple.
Les difficultés que vous rencontrez sont souvent de nature méthodologique. Sur le plan technique, il y a toujours un moyen pour trouver une documentation sur le comment écrire, d'un point de vue syntaxique, tel ou tel appel à une méthode ou fonction Java. Certes, vous rencontrez d'autres problèmes liés au fait que le cours sur les interfaces graphiques en Java arrive juste après les cours introductifs à Java. Tout cela n'est pas grave si nous prenons un peu de recul.
Premier conseil méthodologique : prenez le temps de lire la documentation proposée, toute la documentation. Le programme est construit à partir d'un exemple simple au départ, puis les notions sont introduites progressivement. Partez du code du premier exercice et augmentez le au fur et à mesure de votre progression dans l'ajout de fonctionnalités. Ne redéveloppez pas complètement à chaque nouvel exercice. Autrement dit, ne remettez pas tout en cause systématiquement.
Deuxième conseil méthodologique, pour développer. Les composants Swing forment un nouvelle hiérarchie parallèle à celle de AWT. L'ancêtre de cette hiérarchie est le composant JComponent. La procédure à suivre pour utiliser un composant Swing est identique à celle des composants de la bibliothèque AWT : créer le composant en appelant son constructeur, appeler les méthodes du composant si nécessaire pour le personnaliser et l'ajouter dans un conteneur. Les composants Swing utilisent des modèles pour contenir leurs états ou leurs données. Ces modèles sont des classes particulières qui possèdent toutes un comportement par défaut.
Troisième conseil méthodologique. La gestion des événements en SWING est identique à celle utilisée dans AWT. On procède généralement à la définition d'une méthode, ou la redéfinition d'une méthode à déclencher lorsqu'un évènement (souris, clavier...) intervient. Puis il faut appeler une méthode qui va ajouter cette méthode aux écouteurs déjà définis. A ce niveau il faut imaginer que votre programme Java tourne dans une boucle "répéter pour toujours" et, en fonction de l'évènement, décide d'une action à enclencher. Techniquement, on peut procéder de deux manières au moins. Voici la première que vous êtes invités à décoder :
import javax.swing.*; import java.awt.event.*; public class TestJFrame8 { public static void main(String argv[]) { JFrame f = new JFrame("ma fenetre"); f.setSize(300,100); f.setVisible(true); f.addWindowListener(new WindowAdapter() { public void windowClosing(WindowEvent e) { System.exit(0); } } ); } }
On peut aussi écrire :
import javax.swing.*; import java.awt.event.*; public class swing2 extends JFrame { public swing2() { super("titre de l'application"); WindowListener l = new WindowAdapter() { public void windowClosing(WindowEvent e){ System.exit(0); } }; addWindowListener(l); JButton bouton = new JButton("Mon bouton"); JPanel panneau = new JPanel(); panneau.add(bouton); setContentPane(panneau); setSize(200,100); setVisible(true); } public static void main(String [] args){ JFrame frame = new swing2(); } }
Cette non unicité dans l'approche peut conduire à des codes difficilement lisibles. Choisissez une méthodologie... que vous adoptez pour l'ensemble de votre projet. Ne mélangez pas les méthodologies.
Quatrième conseil méthodologique. Reportez-vous toujours à un dessin qui représente la hiérachie des classes pour repérer comment on doit lier les éléments graphiques les uns avec les autres. Par exemple, considérons la hiérarchie suivante :
Nous voyons ici que tous les composants associés à un objet JFrame
sont gérés par un objet de la classe JRootPane. Un objet JRootPane
contient plusieurs Panes. Tous les composants ajoutés au JFame doivent
être ajoutés à un des Pane du JRootPane et non au JFrame
directement. C'est aussi à un de ces Panes qu'il faut associer un
layout manager si nécessaire. Rappelons que le layout manager par
défaut du contentPane est BorderLayout... que l'on peut bien entendu
changer par quelque chose qui ressemble
à f.getContentPane().setLayout(new FlowLayout());
Il est
alors d'usage de commencer à empiler les objets dans ce Frame,
toujours en passant par le ContentPane, par exemple avec le
code JButton b =new JButton("Mon bouton");
f.getContentPane().add(b);
En résumé, Le JRootPane se compose de plusieurs éléments :
Le glassPane est un JPanel transparent qui se situe au-dessus du layeredPane. Le glassPane peut être n'importe quel composant : pour le modifier il faut utiliser la méthode setGlassPane() en fournissant le composant en paramètre.
Le layeredPane regroupe le contentPane et le menuBar.
Le contentPane est par défaut un JPanel opaque dont le gestionnaire de présentation est un BorderLayout. Ce panel peut être remplacé par n'importe quel composant grâce à la méthode setContentPane().
Le Code suivant concerne une calculette simple développée en java Swing. Pour ce code, nous vous demandons :
Passons maintenant à tout autre chose. Pour la feuille de TP
concernant la VueStationMeteo
vous avez un peu de mal
avec les panneaux et la politique de placement dans chacun des
panneaux. Nous pouvons toujours commencer par simplifier le sujet pour
construire seulement un panneau nord (avant d'attaquer le sujet avec
tous les panneaux).
Nous pouvons alors ne considérer que JPanel
getPanneauNord(){ }
qui est appelée
par intialise()
. Dans ce panneau, placer au début
seulement 2 JLabels
et 2 zones de
saisie JTextField
. Il convient alors de bien faire la
distinction entre la politique Flow
pour les
éléments placés à l'intérieur de ce
panneau et la politique de placement dans la fenêtre qui permet
de positionner le panneau Nord (politique au niveau de la
fenêtre)
D'ou viennent les difficultés ? De la relation, au niveau de l'API, entre les évênements qui ont été impliqués. Autrement dit, quel est le composant à la source de l'évênement alors que je suis en train de programmer un certain "composant" ? Par exemple, lorsqu'un composant fenêtre reçoit un événement FOCUS_LOST, ce composant ne peut pas savoir de quel composant il obtient le focus. Cet exemple grossit le trait - il a vocation à illustrer le propos.
Il convient alors d'observer et de comprendre comment le Système (API+évênements) est organisé de manière hiérarchique. Pour notre TD/TP :
initialise()
initialise()
appelle getPanneauXXX()
4 fois et place ces 4 panneaux dans la fenêtre (selon
BorderLayout)
Si vous voulez installer GTK sur MacOs, veuillez suivre ce lien. Si vous êtes sous Linux, GTK est plus facilement accessible.
Le langage de programmation Go est poussé par Google. Il ressemble à du Java. Pour pousser à l'adoption, la documentation dit :
Go is expressive, concise, clean, and efficient. Its concurrency mechanisms make it easy to write programs that get the most out of multicore and networked machines, while its novel type system enables flexible and modular program construction. Go compiles quickly to machine code yet has the convenience of garbage collection and the power of run-time reflection. It's a fast, statically typed, compiled language that feels like a dynamically typed, interpreted language.
Pour pouvoir construire des interfaces graphiques avec Go et GTK, il faut suivre cette installation. La méthode de construction que je recommande est :
# go get github.com/mattn/go-gtk/gtk # cd $HOME/go/src/go-gtk # make install # make example # ./example/demo/demo
Note : je suppose que la variable d'environnement GOPATH est $HOME/go
L'exécution de l'exemple, via la ligne de commande ./example/demo/demo donne l'interface graphique :
Le code source de l'exemple est :
Avec l'apparition de Java 8 en mars 2014, JavaFX devient la bibliothèque de création d'interface graphique officielle du langage Java, pour toutes sortes d'applications (applications mobiles, applications sur poste de travail, applications Web), le développement de son prédécesseur Swing étant abandonné (sauf pour les corrections de bogues).
De nombreux tutoriels existent, dont celui-ci (en anglais). Cette page explique comment installer, utiliser... et concevoir une application JavaFX.
De nombreuses bibliothèques sont maintenant disponibles pour programmer des interfaces graphiques dans le contexte HTML/javascript. Elles ont vu le jour sous la poussée de plus en plus importante du navigateur pour accéder aux applications. Celà correspond à un mouvement général qui est lié aux technologies du cloud et aux SaaS (Sotfware as a Service). Il s'agit donc d'accèder à un service, à la demande, ce service étant externalisé et accessible via un serveur Web (Apache par exemple). Ce mouvement est plus vaste que la location de logiciels puisqu'il touche maintenant de nombreux secteurs : bibliothèques musicales et vidéo (Apple Music, Netflix...), voiturage et co-voiturage (Blablacar...), achat de voitures en leasing, abonnements à des journaux où vous ne recevez plus la version papier mais où la version digitale est en ligne...
Pour que cette vision commerciale puisse se réaliser, le navigateur doit être au coeur de l'informatique, c'est à dire que le navigateur doit être le Système d'exploitation comme Windows ou Linux est le système d'exploitation pour les machines à la maison (Desktop PC). Le bon côté des choses c'est que l'informaticien n'a plus à ce soucier s'il doit développer pour MacOS, Windows, Linux, Android, IoS... Il va simplement demander à l'utilisateur final du service de disposer d'un navigateur. Or, tout le monde à un navigateur à porté de main. L'informaticien est devenu un développeur d'applications universelles.
Alors pourquoi apprendre Java Swing qui est une technologie que l'on déploie sur le Desktop PC ? C'est une bonne question d'autant plus que plus grand monde n'utilise des applications qui sont installées sur le Desktop PC. L'autre bonne question est : mais quel est ce langage qui fait que le navigateur est au coeur des développements ? Il s'agit de JavaScript. En effect, tous les navigateurs embarquent une machine virtuelle Javascript et Mozilla est un acteur important pour sa normalisation. Ainsi, tous les navigateurs savent interpréter les codes HTML, CSS et Javascript qu'ils reçoivent suite à une requête.
Les bibliothèques Javascript qui font parties de l'écosystème du Web pour développer des interfaces graphiques sont React, VueJS, EmberJS pour ne citer que les plusemblématiques. Chacune d'entre elles permet de programmer le côté Vue du modèle MVC. En effet, une application c'est d'abord un modèle de la réalité et une partie controleur qui correspond aux contrôle du flux d'exécution des instructions du programme sur des données. Par exemple, pour une compagnie aérienne nous allons la modéliser (en partie) par une table Pilotes et nous allons mettre en oeuvre (via le controleur) les opérations d'insertion, modification, suppression d'un pilote.
Vous allez me dire maintenant que Java Swing est beaucoup mieux que ces librairies parce que nous pouvons développer chaque partie du modèle MVC. C'est pas faux ! Mais en fait, du coté du Web, il y a maintenant un framework complet de développement qui s'appelle AngularJS. Une page web conçue avec AngularJS suit le patron d'architecture MVC (modèle-vue-contrôleur). Ce patron a pour avantage de proposer un couplage faible entre la présentation, les données, et les composants métier.
Vous pouvez trouver des tutoriels sur les 3 librairies React, VueJS et EmberJS en parcourant les liens suivants :
Bien entendu, les composants graphiques que l'on va gérer avec les librairies sont des éléments HTML (Cartes, SVG, Canvas, Game), ou encore les bouttons CSS, voire les zones de texte ou les tables HTML.
Christophe Cérin
christophe.cerin@univ-paris13.fr
April 21, 2020