|
|
13) Création de fenêtres & d'Applets |
|
|
|
Texte original |
|
Traducteur :
P. Boite |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
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).
|
|
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).
|
|
|
|
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!).
|
|
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">
|
|
|
|
The clipboard
|
|
Le presse-papier [clipboard]
|
|
|
|
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.
|
|
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.
|
|
|
|
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.
|
|
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.
|
|
|
|
//: 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);
}
} ///:~
|
|
//: 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); } } ///:~
|
|
|
|
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.
|
|
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.
|
|
|
|
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.
|
|
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.
|
|
|
|
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.
|
|
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.
|
|
|
|
In the future you can expect more data
flavors to be
supported.
|
|
Dans le futur, on peut s'attendre à ce qu'il y ait plus de flavors
acceptés.
|
|
|
|
Packaging an applet into a JAR
file
|
|
Empaquetage d'une applet dans un fichier JAR
|
|
|
|
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.
|
|
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.
|
|
|
|
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.
|
|
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.
|
|
|
|
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:
|
|
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 :
|
|
|
|
jar cf TicTacToe.jar *.class
|
|
jar cf TicTacToe.jar *.class
|
|
|
|
This assumes that the only .class
files in the current directory are the ones from TicTacToe.java
(otherwise you’ll get extra baggage).
|
|
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).
|
|
|
|
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:
|
|
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 :
|
|
|
|
<head><title>TicTacToe Example Applet
</title></head>
<body>
<applet code=TicTacToe.class
archive=TicTacToe.jar
width=200 height=100>
</applet>
</body>
|
|
<head><title>TicTacToe Example Applet </title></head> <body> <applet code=TicTacToe.class archive=TicTacToe.jar width=200 height=100> </applet> </body>
|
|
|
|
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"> |
|
Il faudra le mettre dans la nouvelleforme (confuse, compliquée) montrée plus haut dans ce chapitre pour le
faire fonctionner.
|
|
|
|
Programming techniques
|
|
Techniques de programmation
|
|
|
|
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.
|
|
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.
|
|
|
|
Binding events dynamically
|
|
Lier des événements dynamiquement
|
|
|
|
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:
|
|
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 :
|
|
|
|
//: 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);
}
} ///:~
|
|
//: 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); } } ///:~
|
|
|
|
The new twists in this example are:
|
|
Les nouvelles astuces dans cet exemple sont :
|
|
|
|
- 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.
- 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.
|
|
- 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.
- 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.
|
|
|
|
This kind of
flexibility provides much greater power in your programming.
|
|
Ce genre de flexibilité permet une grande puissance de
programmation.
|
|
|
|
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).
|
|
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).
|
|
|
|
Separating business logic from UI logic
|
|
Séparation entre la logique applicative [business logic] et la
logique de l'interface utilisateur [UI logic]
|
|
|
|
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. |
|
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.
|
|
|
|
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.
|
|
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.
|
|
|
|
The following example shows how easy it
is to separate the business logic from the GUI code:
|
|
L'exemple suivant montre comme il est facile de séparer la logique
applicative du code GUI :
|
|
|
|
//: 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);
}
} ///:~
|
|
//: 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); } } ///:~
|
|
|
|
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.
|
|
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.
|
|
|
|
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.
|
|
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.
|
|
|
|
Thinking in terms of separating UI from
business logic also makes life easier when you’re adapting legacy code to
work with Java.
|
|
Penser à séparer l'interface utilisateur de la logique applicative facilite
également l'adaptation de code existant pour fonctionner avec Java.
|
|
|
|
A canonical form
|
|
Une forme canonique
|
|
|
|
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.
|
|
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.
|
|
|
|
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.
|
|
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.
|
|
|
|
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.
|
|
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.
|
|
|
|
|
|
|
|
|
|
|
|
|