t
t
t
t
t t   13) Création de fenêtres & d'Applets
tttt
t
carrea) Préface carreb) Avant-propos carre1) Introduction sur les &laqo; objets » carre2) Tout est &laqo; objet » carre3) Contrôle du flux du programme carre4) Initialization & Cleanup carre5) Cacher l'implémentation carre6) Réutiliser les classes carre7) Polymorphisme carre8) Interfaces & classes internes carre9) Stockage des objets carre10) Error Handling with Exceptions carre11) Le système d’E/S de Java carre12) Identification dynamique de type 13) Création de fenêtres & d'Applets carre14) Les &laqo; Threads » multiples carre15) Informatique distribuée carreA) Passage et retour d'objets carreB) L'Interface Java Natif (JNI) carreC) Conseils pour une programation stylée en Java carreD) Resources
Texte original t Traducteur : P. Boite
t
t
///
Ce chapitre contient 14 pages
1 2 3 4 5 6 7 8 9 10 11 12 13 14
\\\
t t t
t t t
t
t t t
You can see that one option is to explicitly specify a string for a look and feel, as seen with MotifLookAndFeel. However, that one and the default “metal” look and feel are the only ones that can legally be used on any platform; even though there are strings for Windows and Macintosh look and feels, those can only be used on their respective platforms (these are produced when you call getSystemLookAndFeelClassName( ) and you’re on that particular platform). t On peut voir qu'une option permet de spécifier explicitement une chaîne pour un look and feel donné, comme par exemple MotifLookAndFeel. Toutefois seuls celui-ci et le look and feel metal sont les seuls à pouvoir être utilisés légalement sur toute plateforme ; bien qu'il existe des chaînes pour les look and feels Windows et Macintosh, ceux-ci ne peuvent être utilisés que sur leurs plateformes respectives (ceux-ci sont fournis lorsqu'on appelle getSystemLookAndFeelClassName() et qu'on est sur cette plateforme donnée).
t t t
It is also possible to create a custom look and feel package, for example, if you are building a framework for a company that wants a distinctive appearance. This is a big job and is far beyond the scope of this book (in fact, you’ll discover it is beyond the scope of many dedicated Swing books!).
t Il est également possible de créer un package de look and feel sur mesure, par exemple si on crée un environnement de travail pour une société qui désire une apparence spéciale. C'est un gros travail qui est bien au-delà de la portée de ce livre (en fait vous découvrirez qu'il est au-delà de la portée de beaucoup de livres dédiés à Swing).name="_Toc481064830">
t t t

The clipboard

t

Le presse-papier [clipboard]

t t t
The JFC supports limited operations with the system clipboard (in the java.awt.datatransfer package). You can copy String objects to the clipboard as text, and you can paste text from the clipboard into String objects. Of course, the clipboard is designed to hold any type of data, but how this data is represented on the clipboard is up to the program doing the cutting and pasting. The Java clipboard API provides for extensibility through the concept of a “flavor.” When data comes off the clipboard, it has an associated set of flavors that it can be converted to (for example, a graph might be represented as a string of numbers or as an image) and you can see if that particular clipboard data supports the flavor you’re interested in. t JFC permet des opérations limitées avec le presse-papier système (dans le package java.awt.datatransfer). On peut copier des objets String dans le presse-papier en tant que texte, et on peut coller du texte depuis le presse-papier dans des objets String. Bien sûr, le presse-papier est prévu pour contenir n'importe quel type de données, mais la représentation de ces données dans le presse-papier est du ressort du programme effectuant les opérations de couper et coller. L'API Java clipboard permet ces extensions à l'aide du concept de «parfum» [flavor]. Les données en provenance du presse-papier sont associées à un ensemble de flavorsdans lesquels on peut les convertir (par exemple, un graphe peut être représenté par une chaîne de nombres ou par une image) et on peut vérifier si les données contenues dans le presse-papier acceptent le flavor qui nous intéresse.
t t t
The following program is a simple demonstration of cut, copy, and paste with String data in a JTextArea. One thing you’ll notice is that the keyboard sequences you normally use for cutting, copying, and pasting also work. But if you look at any JTextField or JTextArea in any other program you’ll find that they also automatically support the clipboard key sequences. This example simply adds programmatic control of the clipboard, and you could use these techniques if you want to capture clipboard text into something other than a JTextComponent. t Le programme suivant est une démonstration simple de couper, copier et coller des données String dans une face="Georgia">JTextArea. On remarquera que les séquences clavier utilisées normalement pour couper, copier et coller fonctionnent également. Mais si on observe un JTextField ou un JTextArea dans tout autre programme, on verra qu'ils acceptent aussi automatiquement les séquences clavier du presse-papier. Cet exemple ajoute simplement un contrôle du presse-papier par le programme, et on peut utiliser ces techniques pour capturer du texte du presse-papier depuis autre chose qu'un JTextComponent.
t t t
//: c13:CutAndPaste.java // Using the clipboard. import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.awt.datatransfer.*; import com.bruceeckel.swing.*; public class CutAndPaste extends JFrame { JMenuBar mb = new JMenuBar(); JMenu edit = new JMenu("Edit"); JMenuItem cut = new JMenuItem("Cut"), copy = new JMenuItem("Copy"), paste = new JMenuItem("Paste"); JTextArea text = new JTextArea(20, 20); Clipboard clipbd = getToolkit().getSystemClipboard(); public CutAndPaste() { cut.addActionListener(new CutL()); copy.addActionListener(new CopyL()); paste.addActionListener(new PasteL()); edit.add(cut); edit.add(copy); edit.add(paste); mb.add(edit); setJMenuBar(mb); getContentPane().add(text); } class CopyL implements ActionListener { public void actionPerformed(ActionEvent e) { String selection = text.getSelectedText(); if (selection == null) return; StringSelection clipString = new StringSelection(selection); clipbd.setContents(clipString,clipString); } } class CutL implements ActionListener { public void actionPerformed(ActionEvent e) { String selection = text.getSelectedText(); if (selection == null) return; StringSelection clipString = new StringSelection(selection); clipbd.setContents(clipString, clipString); text.replaceRange("", text.getSelectionStart(), text.getSelectionEnd()); } } class PasteL implements ActionListener { public void actionPerformed(ActionEvent e) { Transferable clipData = clipbd.getContents(CutAndPaste.this); try { String clipString = (String)clipData. getTransferData( DataFlavor.stringFlavor); text.replaceRange(clipString, text.getSelectionStart(), text.getSelectionEnd()); } catch(Exception ex) { System.err.println("Not String flavor"); } } } public static void main(String[] args) { Console.run(new CutAndPaste(), 300, 200); } } ///:~ t
//: c13:CutAndPaste.java
// Utilisation du presse-papier.
importjavax.swing.*;
importjava.awt.*;
importjava.awt.event.*;
importjava.awt.datatransfer.*;
importcom.bruceeckel.swing.*;

publicclassCutAndPaste extendsJFrame  {
JMenuBar mb = newJMenuBar();
JMenu edit = newJMenu("Edit");
JMenuItem
   cut = newJMenuItem("Cut"),
   copy = newJMenuItem("Copy"),
   paste = newJMenuItem("Paste");
JTextArea text = newJTextArea(20, 20);
Clipboard clipbd =
   getToolkit().getSystemClipboard();
publicCutAndPaste()  {
   cut.addActionListener(newCutL());
   copy.addActionListener(newCopyL());
   paste.addActionListener(newPasteL());
   edit.add(cut);
   edit.add(copy);
   edit.add(paste);
   mb.add(edit);
   setJMenuBar(mb);
   getContentPane().add(text);
}
classCopyL implementsActionListener {
   publicvoidactionPerformed(ActionEvent e) {
     String selection = text.getSelectedText();
     if(selection == null)
       return;
     StringSelection clipString =       newStringSelection(selection);
     clipbd.setContents(clipString,clipString);
   }
}
classCutL implementsActionListener {
   publicvoidactionPerformed(ActionEvent e) {
     String selection = text.getSelectedText();
     if(selection == null)
       return;
     StringSelection clipString =       newStringSelection(selection);
     clipbd.setContents(clipString, clipString);
     text.replaceRange("",
       text.getSelectionStart(),
       text.getSelectionEnd());
   }
}
classPasteL implementsActionListener {
   publicvoidactionPerformed(ActionEvent e) {
     Transferable clipData =       clipbd.getContents(CutAndPaste.this);
     try{
       String clipString =         (String)clipData.
           getTransferData(
             DataFlavor.stringFlavor);
       text.replaceRange(clipString,
         text.getSelectionStart(),
         text.getSelectionEnd());
     } catch(Exception ex) {
       System.err.println("Not String flavor");
     }
   }
}
publicstaticvoidmain(String[] args) {
   Console.run(newCutAndPaste(), 300, 200);
}
} ///:~
t t t
The creation and addition of the menu and JTextArea should by now seem a pedestrian activity. What’s different is the creation of the Clipboard field clipbd, which is done through the Toolkit. t La création et l'ajout du menu et du JTextArea devraient être maintenant une activité naturelle. Ce qui est différent est la création du champ Clipboard clipbd, qui est faite à l'aide du Toolkit.
t t t
All the action takes place in the listeners. The CopyL and CutL listeners are the same except for the last line of CutL, which erases the line that’s been copied. The special two lines are the creation of a StringSelection object from the String and the call to setContents( ) with this StringSelection. That’s all there is to putting a String on the clipboard. t Toutes les actions sont effectuées dans les listeners. Les listeners CopyL et CutL sont identiques à l'exception de la dernière ligne de CutL, qui efface la ligne qui a été copiée. Les deux lignes particulières sont la création d'un objet StringSelection à partir du String, et l'appel à setContents() avec ce StringSelection. C'est tout ce qu'il y a à faire pour mettre une String dans le presse-papier.
t t t
In PasteL, data is pulled off the clipboard using getContents( ). What comes back is a fairly anonymous Transferable object, and you don’t really know what it contains. One way to find out is to call getTransferDataFlavors( ), which returns an array of DataFlavor objects indicating which flavors are supported by this particular object. You can also ask it directly with isDataFlavorSupported( ), passing in the flavor you’re interested in. Here, however, the bold approach is taken: getTransferData( ) is called assuming that the contents supports the String flavor, and if it doesn’t the problem is sorted out in the exception handler. t Dans PasteL, les données sont extraites du presse-papier à l'aide de name="Index1777">getContents(). Ce qu'il en sort est un objet Transferableassez anonyme, et on ne sait pas exactement ce qu'il contient. Un moyen de le savoir est d'appeler getTransferDataFlavors(), qui renvoie un tableau d'objets name="Index1780">DataFlavorindiquant quels flavors sont acceptés par cet objet. On peut aussi le demander directement à l'aide de isDataFlavorSupported(), en passant en paramètre le flavor qui nous intéresse. Dans ce programme, toutefois, on utilise une approche téméraire : on appelle getTransferData()en supposant que le contenu accepte le flavor String, et si ce n'est pas le cas le problème est pris en charge par le traitement d'exception.
t t t
In the future you can expect more data flavors to be supported.
t Dans le futur, on peut s'attendre à ce qu'il y ait plus de flavors acceptés.
t t t

Packaging an applet into a JAR file

t

Empaquetage d'une applet dans un fichier JAR

t t t
An important use of the JAR utility is to optimize applet loading. In Java 1.0, people tended to try to cram all their code into a single applet class so the client would need only a single server hit to download the applet code. Not only did this result in messy, hard to read (and maintain) programs, but the .class file was still uncompressed so downloading wasn’t as fast as it could have been. t Une utilisation importante de l'utilitaire JAR est l'optimisation du chargement d'une applet. En Java 1.0, les gens avaient tendance à entasser tout leur code dans une seule classe, de sorte que le client ne devait faire qu'une seule requête au serveur pour télécharger le code de l'applet. Ceci avait pour résultat des programmes désordonnés, difficiles à lire (et à maintenir), et d'autre part le fichier .class n'était pas compressé, de sorte que le téléchargement n'était pas aussi rapide que possible.
t t t
JAR files solve the problem by compressing all of your .class files into a single file that is downloaded by the browser. Now you can create the right design without worrying about how many .class files it will generate, and the user will get a much faster download time. t Les fichiers JAR résolvent le problème en compressant tous les fichiers .class en un seul fichier qui est téléchargé par le navigateur. On peut maintenant avoir une conception correcte sans se préoccuper du nombre de fichiers .class qui seront nécessaires, et l'utilisateur aura un temps de téléchargement beaucoup plus court.
t t t
Consider TicTacToe.java. It looks like a single class, but in fact it contains five inner classes, so that’s six in all. Once you’ve compiled the program, you package it into a JAR file with the line: t Prenons par exemple TicTacToe.java. Il apparaît comme une seule classe, mais en fait il contient cinq classes internes, ce qui fait six au total. Une fois le programme compilé on l'emballe dans un fichier JAR avec l'instruction :
t t t
jar cf TicTacToe.jar *.class t
jar cf TicTacToe.jar *.class
t t t
This assumes that the only .class files in the current directory are the ones from TicTacToe.java (otherwise you’ll get extra baggage). t Ceci suppose que dans le répertoire courant il n'y a que les fichiers .class issus de TicTacToe.java (sinon on emporte du bagage supplémentaire).
t t t
Now you can create an HTML page with the new archive tag to indicate the name of the JAR file. Here is the tag using the old form of the HTML tag, as an illustration: t On peut maintenant créer une page HTML avec le nouveau tag name="Index1785">archive pour indiquer le nom du fichier JAR. Voici pour exemple le tag utilisant l'ancienne forme du tag HTML :
t t t
<head><title>TicTacToe Example Applet </title></head> <body> <applet code=TicTacToe.class archive=TicTacToe.jar width=200 height=100> </applet> </body> t
<head><title>TicTacToe Example Applet
</title></head>
<body>
<applet code=TicTacToe.class
       archive=TicTacToe.jar
       width=200 height=100>
</applet>
</body>
t t t
You’ll need to put it into the new (messy, complicated) form shown earlier in the chapter in order to get it to work."_Toc481064832"> t Il faudra le mettre dans la nouvelleforme (confuse, compliquée) montrée plus haut dans ce chapitre pour le faire fonctionner.
t t t

Programming techniques

t

Techniques de programmation

t t t
Because GUI programming in Java has been an evolving technology with some very significant changes between Java 1.0/1.1 and the Swing library in Java 2, there have been some old programming idioms that have seeped through to examples that you might see given for Swing. In addition, Swing allows you to program in more and better ways than were allowed by the old models. In this section, some of these issues will be demonstrated by introducing and examining some programming idioms.
t La programmation de GUI en Java étant une technologie évolutive, avec des modifications très importantes entre Java 1.0/1.1 et la bibliothèque Swing, certains styles de programmation anciens ont pu s'insinuer dans des exemples qu'on peut trouver pour Swing. D'autre part, Swing permet une meilleure programmation que ce que permettaient les anciens modèles. Dans cette partie, certains de ces problèmes vont être montrés en présentant et en examinant certains styles de programmation.
t t t

Binding events dynamically

t

Lier des événements dynamiquement

t t t
One of the benefits of the Swing event model is flexibility. You can add and remove event behavior with single method calls. The following example demonstrates this: t Un des avantages du modèle d'événements Swing est sa flexibilité. On peut ajouter ou retirer un comportement sur événement à l'aide d'un simple appel de méthode. L'exemple suivant le montre :
t t t
//: c13:DynamicEvents.java // You can change event behavior dynamically. // Also shows multiple actions for an event. // <applet code=DynamicEvents // width=250 height=400></applet> import javax.swing.*; import java.awt.*; import java.awt.event.*; import java.util.*; import com.bruceeckel.swing.*; public class DynamicEvents extends JApplet { ArrayList v = new ArrayList(); int i = 0; JButton b1 = new JButton("Button1"), b2 = new JButton("Button2"); JTextArea txt = new JTextArea(); class B implements ActionListener { public void actionPerformed(ActionEvent e) { txt.append("A button was pressed\n"); } } class CountListener implements ActionListener { int index; public CountListener(int i) { index = i; } public void actionPerformed(ActionEvent e) { txt.append("Counted Listener "+index+"\n"); } } class B1 implements ActionListener { public void actionPerformed(ActionEvent e) { txt.append("Button 1 pressed\n"); ActionListener a = new CountListener(i++); v.add(a); b2.addActionListener(a); } } class B2 implements ActionListener { public void actionPerformed(ActionEvent e) { txt.append("Button2 pressed\n"); int end = v.size() - 1; if(end >= 0) { b2.removeActionListener( (ActionListener)v.get(end)); v.remove(end); } } } public void init() { Container cp = getContentPane(); b1.addActionListener(new B()); b1.addActionListener(new B1()); b2.addActionListener(new B()); b2.addActionListener(new B2()); JPanel p = new JPanel(); p.add(b1); p.add(b2); cp.add(BorderLayout.NORTH, p); cp.add(new JScrollPane(txt)); } public static void main(String[] args) { Console.run(new DynamicEvents(), 250, 400); } } ///:~ t
//: c13:DynamicEvents.java
// On peut modifier dynamiquement le comportement sur événement.
// Montre également plusieurs actions pour un événement.
// <applet code=DynamicEvents
//  width=250 height=400></applet>
importjavax.swing.*;
importjava.awt.*;
importjava.awt.event.*;
importjava.util.*;
importcom.bruceeckel.swing.*;

publicclassDynamicEvents extendsJApplet {
ArrayList v = newArrayList();
inti = 0;
JButton
   b1 = newJButton("Button1",
   b2 = newJButton("Button2");
JTextArea txt = newJTextArea();
classB implementsActionListener {
   publicvoidactionPerformed(ActionEvent e) {
     txt.append("A button was pressed\n");
   }
}
classCountListener implementsActionListener {
   intindex;
   publicCountListener(inti) { index = i; }
   publicvoidactionPerformed(ActionEvent e) {
     txt.append("Counted Listener "+index+"\n");
   }
}
classB1 implementsActionListener {
   publicvoidactionPerformed(ActionEvent e) {
     txt.append("Button 1 pressed\n");
     ActionListener a = newCountListener(i++);
     v.add(a);
     b2.addActionListener(a);
   }
}
classB2 implementsActionListener {
   publicvoidactionPerformed(ActionEvent e) {
     txt.append("Button2 pressed\n");
     intend = v.size() - 1;
     if(end >= 0) {
       b2.removeActionListener(
         (ActionListener)v.get(end));
       v.remove(end);
     }
   }
}
publicvoidinit() {
   Container cp = getContentPane();
   b1.addActionListener(newB());
   b1.addActionListener(newB1());
   b2.addActionListener(newB());
   b2.addActionListener(newB2());
   JPanel p = newJPanel();
   p.add(b1);
   p.add(b2);
   cp.add(BorderLayout.NORTH, p);
   cp.add(newJScrollPane(txt));
}
publicstaticvoidmain(String[] args) {
   Console.run(newDynamicEvents(), 250, 400);
}
} ///:~
t t t
The new twists in this example are: t Les nouvelles astuces dans cet exemple sont :
t t t
  1. There is more than one listener attached to each Button. Usually, components handle events as multicast, meaning that you can register many listeners for a single event. In the special components in which an event is handled as unicast, you’ll get a TooManyListenersException.
  2. During the execution of the program, listeners are dynamically added and removed from the Button b2. Adding is accomplished in the way you’ve seen before, but each component also has a removeXXXListener( ) method to remove each type of listener.
t
  1. Il y a plus d'un listener attaché à chaque Button. En règle générale, les composants gèrent les événements en tant que multicast, ce qui signifie qu'on peut enregistrer plusieurs listeners pour un seul événement. Pour les composants spéciaux dans lesquels un événement est géré en tant que unicast, on obtiendra une exception TooManyListenersException.
  2. Lors de l'exécution du programme, les listeners sont ajoutés et enlevés du Button b2 dynamiquement. L'ajout est réalisé de la façon vue précédemment, mais chaque composant a aussi une méthode removeXXXListener() pour enlever chaque type de listener.
t t t
This kind of flexibility provides much greater power in your programming. t Ce genre de flexibilité permet une grande puissance de programmation.
t t t
You should notice that event listeners are not guaranteed to be called in the order they are added (although most implementations do in fact work that way).
t Il faut remarquer qu'il n'est pas garanti que les listeners d'événements soient appelés dans l'ordre dans lequel ils sont ajoutés (bien que la plupart des implémentations le fasse de cette façon).
t t t

Separating business logic
from UI logic

t

Séparation entre la logique applicative [business logic] et la logique de l'interface utilisateur [UI logic]

t t t
In general you’ll want to design your classes so that each one does “only one thing.” This is particularly important when user-interface code is concerned, since it’s easy to tie up “what you’re doing” with “how you’re displaying it.” This kind of coupling prevents code reuse. It’s much more desirable to separate your “business logic” from the GUI. This way, you can not only reuse the business logic more easily, it’s also easier to reuse the GUI. t En général on conçoit les classes de manière à ce que chacune fasse une seule chose. Ceci est particulièrement important pour le code d'une interface utilisateur, car il arrive souvent qu'on lie ce qu'on fait à la manière dont on l'affiche. Ce genre de couplage empêche la réutilisation du code. Il est de loin préférable de séparer la logique applicative de la partie GUI. De cette manière, non seulement la logique applicative est plus facile à réutiliser, mais il est également plus facile de récupérer la GUI.
t t t
Another issue is multitiered systems, where the “business objects” reside on a completely separate machine. This central location of the business rules allows changes to be instantly effective for all new transactions, and is thus a compelling way to set up a system. However, these business objects can be used in many different applications and so should not be tied to any particular mode of display. They should just perform the business operations and nothing more. t Un autre problème concerne les systèmes répartis [multitiered systems], dans lesquels les objets applicatifs se trouvent sur une machine séparée. Cette centralisation des règles applicatives permet des modifications ayant un effet immédiat pour toutes les nouvelles transactions, ce qui est une façon intéressante d'installer un système. Cependant, ces objets applicatifs peuvent être utilisés dans de nombreuses applications, et de ce fait ils ne devraient pas être liés à un mode d'affichage particulier. Ils devraient se contenter d'effectuer les opérations applicatives, et rien de plus.
t t t
The following example shows how easy it is to separate the business logic from the GUI code: t L'exemple suivant montre comme il est facile de séparer la logique applicative du code GUI :
t t t
//: c13:Separation.java // Separating GUI logic and business objects. // <applet code=Separation // width=250 height=150> </applet> import javax.swing.*; import java.awt.*; import javax.swing.event.*; import java.awt.event.*; import java.applet.*; import com.bruceeckel.swing.*; class BusinessLogic { private int modifier; public BusinessLogic(int mod) { modifier = mod; } public void setModifier(int mod) { modifier = mod; } public int getModifier() { return modifier; } // Some business operations: public int calculation1(int arg) { return arg * modifier; } public int calculation2(int arg) { return arg + modifier; } } public class Separation extends JApplet { JTextField t = new JTextField(15), mod = new JTextField(15); BusinessLogic bl = new BusinessLogic(2); JButton calc1 = new JButton("Calculation 1"), calc2 = new JButton("Calculation 2"); static int getValue(JTextField tf) { try { return Integer.parseInt(tf.getText()); } catch(NumberFormatException e) { return 0; } } class Calc1L implements ActionListener { public void actionPerformed(ActionEvent e) { t.setText(Integer.toString( bl.calculation1(getValue(t)))); } } class Calc2L implements ActionListener { public void actionPerformed(ActionEvent e) { t.setText(Integer.toString( bl.calculation2(getValue(t)))); } } // If you want something to happen whenever // a JTextField changes, add this listener: class ModL implements DocumentListener { public void changedUpdate(DocumentEvent e) {} public void insertUpdate(DocumentEvent e) { bl.setModifier(getValue(mod)); } public void removeUpdate(DocumentEvent e) { bl.setModifier(getValue(mod)); } } public void init() { Container cp = getContentPane(); cp.setLayout(new FlowLayout()); cp.add(t); calc1.addActionListener(new Calc1L()); calc2.addActionListener(new Calc2L()); JPanel p1 = new JPanel(); p1.add(calc1); p1.add(calc2); cp.add(p1); mod.getDocument(). addDocumentListener(new ModL()); JPanel p2 = new JPanel(); p2.add(new JLabel("Modifier:")); p2.add(mod); cp.add(p2); } public static void main(String[] args) { Console.run(new Separation(), 250, 100); } } ///:~ t
//: c13:Separation.java
// Séparation entre la logique GUI et les objets applicatifs.
// <applet code=Separation
// width=250 height=150> </applet>
importjavax.swing.*;
importjava.awt.*;
importjavax.swing.event.*;
importjava.awt.event.*;
importjava.applet.*;
importcom.bruceeckel.swing.*;

classBusinessLogic {
privateintmodifier;
publicBusinessLogic(intmod) {
   modifier = mod;
}
publicvoidsetModifier(intmod) {
   modifier = mod;
}
publicintgetModifier() {
   returnmodifier;
}
// Quelques opérations applicatives :
publicintcalculation1(intarg) {
   returnarg * modifier;
}
publicintcalculation2(intarg) {
   returnarg + modifier;
}
}

publicclassSeparation extendsJApplet {
JTextField
   t = newJTextField(15),
   mod = newJTextField(15);
BusinessLogic bl = newBusinessLogic(2);
JButton
   calc1 = newJButton("Calculation 1",
   calc2 = newJButton("Calculation 2");
staticintgetValue(JTextField tf) {
   try{
     returnInteger.parseInt(tf.getText());
   } catch(NumberFormatException e) {
     return0;
   }
}
classCalc1L implementsActionListener {
   publicvoidactionPerformed(ActionEvent e) {
     t.setText(Integer.toString(
       bl.calculation1(getValue(t))));
   }
}
classCalc2L implementsActionListener {
   publicvoidactionPerformed(ActionEvent e) {
     t.setText(Integer.toString(
       bl.calculation2(getValue(t))));
   }
}
// Si vous voulez que quelque chose se passe chaque fois
// qu'un JTextField est modifié, ajoutez ce listener :
classModL implementsDocumentListener {
   publicvoidchangedUpdate(DocumentEvent e) {}
   publicvoidinsertUpdate(DocumentEvent e) {
     bl.setModifier(getValue(mod));
   }
   publicvoidremoveUpdate(DocumentEvent e) {
     bl.setModifier(getValue(mod));
   }
}
publicvoidinit() {
   Container cp = getContentPane();
   cp.setLayout(newFlowLayout());
   cp.add(t);
   calc1.addActionListener(newCalc1L());
   calc2.addActionListener(newCalc2L());
   JPanel p1 = newJPanel();
   p1.add(calc1);
   p1.add(calc2);
   cp.add(p1);
   mod.getDocument().
     addDocumentListener(newModL());
   JPanel p2 = newJPanel();
   p2.add(newJLabel("Modifier:"));
   p2.add(mod);
   cp.add(p2);
}
publicstaticvoidmain(String[] args) {
   Console.run(newSeparation(), 250, 100);
}
} ///:~
t t t
You can see that BusinessLogic is a straightforward class that performs its operations without even a hint that it might be used in a GUI environment. It just does its job. t On peut voir que BusinessLogic est une classe toute simple, qui effectue ses opérations sans même avoir idée qu'elle puisse être utilisée dans un environnement GUI. Elle se contente d'effectuer son travail.
t t t
Separation keeps track of all the UI details, and it talks to BusinessLogic only through its public interface. All the operations are centered around getting information back and forth through the UI and the BusinessLogic object. So Separation, in turn, just does its job. Since Separation knows only that it’s talking to a BusinessLogic object (that is, it isn’t highly coupled), it could be massaged into talking to other types of objects without much trouble. t Separationgarde la trace des détails de l'interface utilisateur, et elle communique avec BusinessLogic uniquement à travers son interface public. Toutes les opérations sont concentrées sur l'échange d'informations bidirectionnel entre l'interface utilisateur et l'objet BusinessLogic. De même, Separation fait uniquement son travail. Comme Separation sait uniquement qu'il parle à un objet BusinessLogic (c'est à dire qu'il n'est pas fortement couplé), il pourrait facilement être transformé pour parler à d'autres types d'objets.
t t t
Thinking in terms of separating UI from business logic also makes life easier when you’re adapting legacy code to work with Java.
t Penser à séparer l'interface utilisateur de la logique applicative facilite également l'adaptation de code existant pour fonctionner avec Java.
t t t

A canonical form

t

Une forme canonique

t t t
Inner classes, the Swing event model, and the fact that the old event model is still supported along with new library features that rely on old-style programming has added a new element of confusion to the code design process. Now there are even more different ways for people to write unpleasant code. t Les classes internes, le modèle d'événements de Swing, et le fait que l'ancien modèle d'événements soit toujours disponible avec de nouvelles fonctionnalités des bibliothèques qui reposent sur l'ancien style de programmation, ont ajouté un nouvel élément de confusion dans le processus de conception du code. Il y a maintenant encore plus de façons d'écrire du mauvais code.
t t t
Except in extenuating circumstances you can always use the simplest and clearest approach: listener classes (typically written as inner classes) to solve your event-handling needs. This is the form used in most of the examples in this chapter. t A l'exception de circonstances qui tendent à disparaître, on peut toujours utiliser l'approche la plus simple et la plus claire : les classes listener (normalement des classes internes) pour tous les besoins de traitement d'événements. C'est la forme utilisée dans la plupart des exemples de ce chapitre.
t t t
By following this model you should be able to reduce the statements in your programs that say: “I wonder what caused this event.” Each piece of code is concerned with doing, not type-checking. This is the best way to write your code; not only is it easier to conceptualize, but much easier to read and maintain.
t En suivant ce modèle on devrait pouvoir réduire les lignes de programmes qui disent : «Je me demande ce qui a provoqué cet événement». Chaque morceau de code doit se concentrer sur une action, et non pas sur des vérifications de types. C'est la meilleure manière d'écrire le code; c'est non seulement plus facile à conceptualiser, mais également beaucoup plus facile à lire et à maintenir.
t t t
t t t
t t
\\\
///
t t t
t
     
Sommaire Le site de Bruce Eckel