Cours 10

publicité
Notes de cours A
Les fenêtres et les GUI.
Pourquoi les fenêtres ?
S’il vous arrive parfois d’aller télécharger une petite application sur Internet, vous
avez sûrement remarqué que ces programmes, aussi simples puissent-ils être, ont presque
toujours des interfaces graphiques à deux dimensions. Ce type d’interface, composée de
fenêtres, d’images, de boutons, etc. est appelé GUI ( Graphics User Interface ) dans le
langage des initiés. Ces fenêtres, largement utilisées chez les utilisateurs MAC depuis
presque le tout début ne sont monnaie courante chez les mordus PC que depuis 95, années de
la sortie du système d’exploitation Windows 95 (Je sais il y a eu OS/2).
Depuis, d’autres ont suivit, dont Linux, OPEN-VMS et j’en passe. Aujourd’hui, seuls
les « cracks », que vous n’utilisez probablement pas, les « patchs » et autres petits
programmes de groupuscules, souvent aux limites de la légalité, sont encore interfacés en
ligne de commande (hors mis quelques application bancaire, allez savoir pouquoi). Il ne vous
viendrait sûrement pas à l’idée d’utiliser un programme en ligne de commande lorsqu’un avec
GUI est disponible. Peu importe la qualité du produit, ce qui compte, c’est qu’il soit facile à
utiliser, qu’il ait un beau nom et un logo.
C’est le monde dans lequel nous vivons maintenant. Ce que je veux qui soit clair dans
vos têtes, c’est que le contenant est aussi important que le contenu lorsque vient le temps de
mettre en marché un produit, Microsoft nous là bien prouvé depuis plusieurs années. Par
contre, il n’est pas obligatoire de programmer son interface et son moteur en même temps et
en étroite relation, et c’est même déconseillé. Même si plusieurs langages de 4ième génération
fusionnent le code et l’interface usager (VB), ce n’est pas le meilleur moyen de programmer
et sûrement pas le moyen d’avoir les meilleurs résultats.
Une interface complètement indépendante du moteur dans un programme permet de
pouvoir modifier l’interface facilement, de réparer un bogue éventuel du moteur sans se
perdre dans un tissus d’actions ou de fenêtres ayant des accès souvent tirés par les cheveux.
Le conseil du jour : programmer vos applications en ligne de commandes pour
tout ce qui est possible. Lorsque l’absence d’une interface GUI deviendra un obstacle à la
poursuite de votre développement, alors vous pourrez commencer à concevoir votre interface
utilisateur, indépendamment du moteur. Ce n’est, encore là, que lorsque l’absence du moteur
deviendra un frein à l’avancement de votre interface que vous intégrerez les deux ensembles.
Les raisons qui poussent à ces choix sont simples :
1. Encapsulation
2. Modularité
3. Interface stable
4. Application stable
5. Programmation anti-erreur
6. Portabilité
7. Entretien
Je vous mentirais si j’écrivais qu’il n’y a pas de défaut à ce mode de développement.
Les méthodes modernes de développement comme RAD (rapid application développement)
n’ont pour but, souvent, que la livraison le plus rapidement possible d’une version bêta d’un
programme. Hors, le conseil du jour peut prendre plus de temps pour de petites applications.
De plus, pour de très gros projets, il peut être important de bien découper le travail pour que
chaque partie fonctionne bien et en tel cas il est difficile de n’interfacer qu’à la fin.
En conclusion, faites des interfaces usager conviviales et plaisantes pour l’œil.
Cependant, ne faites pas une religion de notions de programmation orientée objet lorsque le
temps de monter le moteur de votre application est venu. Garder toujours en tête le fait que
votre code doit être réutilisable et modifiable.
Les fenêtres en JAVA :
Comme je vous l’ai martelé depuis le début de ce cours, l’un des buts de JAVA est de
permettre de programmer une chose une seule fois et que cela fonctionne partout pour
toujours (program once, run everywhere). Bien sûr, cela est un beau rêve théorique pour
prêtre de la P.O.O. seulement. Mais cela ne veut pas dire que de viser ce but n’est pas noble.
Pour ce qui est des interfaces usagers graphiques (GUI), le même but est visé par
l’implantation de classes les plus indépendantes de la plate-forme possible. Bien sûr, à un
certain niveau notre application doit communiquer avec le système d’exploitation, mais ces
appels de fonctions de l’OS sont réduits au minimum en JAVA. En fait, certaines
classes largement utilisées dans les GUI sont complètement indépendantes du système
d’exploitation. On appelle ces composants : composants légers. Ceux qui sont dépendants,
aussi peu soit-il, de la plate-forme sont appelés composants lourds. Voici un graphique
représentant les notions d’héritages liés aux différentes fenêtres.
Voici une courte description de ces classes.
Window :
Frame :
JFrame :
Dialog :
Fenêtre de haut niveau sans menu ni bordure.
Fenêtre de haut niveau avec titre et bordure.
Version de Frame étendue permettant l’utilisation de composants JFC1/swing.
Fenêtre de haut niveau ayant un titre et une bordure, utilisé pour l’entré de
données par l’usager.
JDialog :
Fenêtre la plus utilisé pour l’entrée de donnée particulièrement à l’aide de la
class JOptionPane.
JWindows : Contenant pouvant être afficher partout sur le bureau, sans boutons de contrôle
ni titre.
Applet :
Petite application qui ne fonctionne pas seule, mais qui doit être exécuter à
l’intérieur d’un autre programme.
JApplet :
Version de Applet supportant l’utilisation de composants JFC/swing.
JInternalFrame : Objet léger permettant certains comportements d’un « Frame » (fermeture,
iconification, modification de la taille, titre, barre des menus.
JRootPane : Objets légers utilisés en arrière plan par les JFrame, JDialog, JWindow et les
JApplet. Nous étudierons plus en détails le JRootPane à la section suivante.
1
Java Foundation Class
Le JRootPane :
Le JRootPane est composé de plusieurs couches, représentés par des membres (objets)
de différentes classes. C’est avec cette classe que nous travaillerons presque toujours lorsque
nous ferons des fenêtres. Que ce soit pour ajouter, enlever, changer le gestionnaire
d’affichage, nous travaillerons toujours sur celui-ci et non sur la fenêtre.
Il y a d’abord, le « contentPane » qui est de type « Container », c’est dans celui-ci que
l’on mettra tous les objets que l’on veux dans notre fenêtre « JFC/swing ». Celui-ci est
accompagné d’un « JMenuBar » optionnel. Ces deux objets ensembles forment une couche
d’un JLayeredPane (Layer : règle). Le tout est recouvert d’un « glassPane » de type
Component qui reçoit les cliques de la souris, indépendant du « contentPane » et invisible par
défaut. Le tout forme un JRootPane. Vous avez ici un graphique représentant ces relations,
notons qu’ici les lignes représentent les membres et non les notions d’héritage.
Dans le cadre du cours, nous n’utiliserons que le « contentPane » pour afficher, et
traiter les évènements. Rappelez-vous seulement qu’il y a plusieurs couches dans une fenêtre
et que l’on peu les empiler.
Les gestionnaires d’affichage :
Les gestionnaires d’affichage servent à gérer l’affichage des « Container ».
L’avantage de ce type de gestion, en opposition à une gestion statique, est qu’il est plus facile
d’obtenir une interface semblable indépendamment de la plate-forme et de la taille de la
fenêtre. Pour assigner un gestionnaire à un « Container » on utilise la méthode « setLayout().
Cela peut se faire en exécution, il suffit de faire réafficher la fenêtre pour voir le résultat.
Regardons un exemple un peu plus complexe de fenêtre avec plusieurs couche (layer), et
quelque composant que nous n’avions pas encore utilisé.
LayeredPaneDemo.java
/* diponible sur
* http://java.sun.com/docs/books/tutorial/uiswing/components/rootpane.html*/
import javax.swing.*;
import javax.swing.border.*;
import javax.accessibility.*;
import java.awt.*;
import java.awt.event.*;
public class LayeredPaneDemo extends JFrame
{
private String[]
layerStrings ={
"Yellow (0)",
"Magenta (1)",
"Cyan (2)",
"Red (3)",
"Green (4)" };
private Color[]
layerColors = {
Color.yellow,
Color.magenta,
Color.cyan,
Color.red,
Color.green };
private JComboBox
private JCheckBox
private JLayeredPane
private JLabel
layerList;
onTop;
layeredPane;
dukeLabel;
public LayeredPaneDemo()
{
super("LayeredPaneDemo");
// titre de la fenêtre
//Creer et placer la Panneau à règle (layered pane).
layeredPane = new JLayeredPane();
layeredPane.setPreferredSize(new Dimension(300, 310));
layeredPane.setBorder(BorderFactory.createTitledBorder(
"Move the Mouse to Move Duke"));
//Creer et charger l'icone Duke.
ImageIcon icon = new ImageIcon("dukeWaveRed.gif");
//Cree et ajoute Duke au panneau de règle à 20, 200 sans changer sa taille.
dukeLabel = new JLabel(icon);
dukeLabel.setBounds(20, 20, icon.getIconWidth(), icon.getIconHeight());
layeredPane.add(dukeLabel, new Integer(2), 0);
Point origin = new Point(10, 20); //origine du premier rectangle
int deplacement = 35;
//le déplacement en x et y
//Nous allons maintenant ajouter des étiquettes (label)
//colorés au panneau à règle, en utilisant la notation absolue
//pour la taille et la position.
for (int i = 0; i < layerStrings.length; i++)
{
JLabel label = creeEtiquetteDeCouleur(
layerStrings[i],
layerColors[i],
origin);
layeredPane.add(label, new Integer(i));
origin.x = origin.x + deplacement;
origin.y = origin.y + deplacement;
}
//Ajouter le panneau de control et le panneau à règle à la fenêtre
//On laisse des espaces verticaux grace à Box.createRigidArea, qui crée
// un composant de taille static.
Container contentPane = getContentPane();
contentPane.setLayout(new BoxLayout(contentPane, BoxLayout.Y_AXIS));
contentPane.add(Box.createRigidArea(new Dimension(0, 10)));
//Espace
contentPane.add(CreePanneauDeControl());
contentPane.add(Box.createRigidArea(new Dimension(0, 10)));
//Espace
contentPane.add(layeredPane);
//Écouteur anonyme d'une classe anonyme
layeredPane.addMouseMotionListener(new MouseMotionAdapter()
{
final int XFUDGE = 40;
//La largeur de Duke
final int YFUDGE = 57;
//La hauteur de Duke
public void mouseMoved(MouseEvent e)
{
dukeLabel.setLocation(e.getX()-XFUDGE, e.getY()-YFUDGE);
}
});
}
//Cree et place des étiquette de couleur
private JLabel creeEtiquetteDeCouleur(String text, Color color, Point origin)
{
JLabel label = new JLabel(text);
label.setVerticalAlignment(JLabel.TOP);
label.setHorizontalAlignment(JLabel.CENTER);
label.setOpaque(true);
label.setBackground(color);
label.setForeground(Color.black);
label.setBorder(BorderFactory.createLineBorder(Color.black));
label.setBounds(origin.x, origin.y, 140, 140);
return label;
}
//Cree le panneau de control pour le haut de la fenêtre
private JPanel CreePanneauDeControl()
{
onTop = new JCheckBox("Top Position in Layer");
onTop.setSelected(true);
onTop.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent e)
{
if (onTop.isSelected())
layeredPane.moveToFront(dukeLabel);
else
layeredPane.moveToBack(dukeLabel);
}
});
layerList = new JComboBox(layerStrings);
layerList.setSelectedIndex(2);
//Cyan layer
layerList.addActionListener(new ActionListener ()
{
public void actionPerformed(ActionEvent e)
{
int position = 1;
if (onTop.isSelected())
position = 0;
layeredPane.setLayer(dukeLabel, layerList.getSelectedIndex(), position);
}
});
JPanel controls = new JPanel();
controls.add(layerList);
controls.add(onTop);
controls.setBorder(BorderFactory.createTitledBorder("Choose Duke's Layer and Position"));
return controls;
}
public static void main(String[] args)
{
JFrame Fenetre = new LayeredPaneDemo();
Fenetre.addWindowListener(new WindowAdapter()
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
});
Fenetre.pack();
Fenetre.setVisible(true);
}
}
Téléchargement