Ceci ajoute un peu de complexité à ce qui est un processus simple. Pour
obtenir un comportement de "OU exclusif" avec des boutons, on crée un groupe de boutons et on
ajoute au groupe chaque bouton pour lequel on désire ce comportement. Lorsqu'on exécute le
programme, on voit que tous les boutons, à l'exception de JButton, montrent ce
comportement de "OU exclusif".
Icones
On peut utiliser un Icon dans un JLabel
ou tout ce qui hérite de AbstractButton (y compris JButton,
JCheckBox, JRadioButton, et les différents types de
JMenuItem). L'utilisation d'Icons avec des
JLabels est assez directe (on verra un exemple plus tard). L'exemple suivant
explore toutes les façons d'utiliser des Icons avec des boutons et leurs
descendants.
Vous pouvez utiliser les fichiers gif que vous voulez, mais ceux utilisés
dans cet exemple font partie de la livraison du code de ce livre, disponible à
www.BruceEckel.com. Pour ouvrir un fichier et utiliser l'image, il suffit de créer un
ImageIcon et de lui fournir le nom du fichier. A partir de là on peut utiliser
l'Icon obtenu dans le programme.
Remarquez que l'information de chemin est codée en dur dans cet exemple;
vous devrez changer ce chemin pour qu'il corresponde à l'emplacement des fichiers des
images.
//: c13:Faces.java
// Comportement des Icones dans des Jbuttons.
// <applet code=Faces
// width=250 height=100></applet>
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.bruceeckel.swing.*;
public class Faces extends JApplet {
// L'information de chemin suivante est nécessaire
// pour l'exécution via une applet directement depuis le disque :
static String path =
"C:/aaa-TIJ2-distribution/code/c13/";
static Icon[] faces = {
new ImageIcon(path + "face0.gif"),
new ImageIcon(path + "face1.gif"),
new ImageIcon(path + "face2.gif"),
new ImageIcon(path + "face3.gif"),
new ImageIcon(path + "face4.gif"),
};
JButton
jb = new JButton("JButton", faces[3]),
jb2 = new JButton("Disable");
boolean mad = false;
public void init() {
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
jb.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
if(mad) {
jb.setIcon(faces[3]);
mad = false;
} else {
jb.setIcon(faces[0]);
mad = true;
}
jb.setVerticalAlignment(JButton.TOP);
jb.setHorizontalAlignment(JButton.LEFT);
}
});
jb.setRolloverEnabled(true);
jb.setRolloverIcon(faces[1]);
jb.setPressedIcon(faces[2]);
jb.setDisabledIcon(faces[4]);
jb.setToolTipText("Yow!");
cp.add(jb);
jb2.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
if(jb.isEnabled()) {
jb.setEnabled(false);
jb2.setText("Enable");
} else {
jb.setEnabled(true);
jb2.setText("Disable");
}
}
});
cp.add(jb2);
}
public static void main(String[] args) {
Console.run(new Faces(), 400, 200);
}
} ///:~
Un Icon peut être utilisé dans de nombreux constructeurs,
mais on peut aussi utiliser setIcon() pour ajouter ou changer un
Icon. Cet exemple montre également comment un JButton (ou un
quelconque AbstractButton) peut positionner les différentes sortes d'icones qui
apparaissent lorsque des choses se passent sur ce bouton : lorsqu'il est enfoncé, invalidé, ou
lorsqu'on roule par dessus [rolled over] (la souris passe au-dessus sans cliquer). On
verra que ceci donne au bouton une sensation d'animation agréable.
Infobulles [Tooltips]
L'exemple précédent ajoutait un tool tip au bouton. La plupart des
classes qu'on utilisera pour créer une interface utilisateur sont dérivées de
JComponent, qui contient une méthode appelée
setToolTipText(String). Donc pratiquement pour tout ce qu'on place sur un
formulaire, il suffit de dire (pour un objet jc de toute classe dérivée de
JComponent) :
jc.setToolTipText("My tip");
et lorsque la souris reste au-dessus de ce JComponent pour un temps
prédéterminé, une petite boîte contenant le texte va apparaître à côté de la souris.
Champs de texte [Text Fields]
Cet exemple montre le comportement supplémentaire dont sont capables les
JTextFields :
//: c13:TextFields.java
// Champs de texte et événements Java.
// <applet code=TextFields width=375
// height=125></applet>
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;
import java.awt.*;
import java.awt.event.*;
import com.bruceeckel.swing.*;
public class TextFields extends JApplet {
JButton
b1 = new JButton("Get Text"),
b2 = new JButton("Set Text");
JTextField
t1 = new JTextField(30),
t2 = new JTextField(30),
t3 = new JTextField(30);
String s = new String();
UpperCaseDocument
ucd = new UpperCaseDocument();
public void init() {
t1.setDocument(ucd);
ucd.addDocumentListener(new T1());
b1.addActionListener(new B1());
b2.addActionListener(new B2());
DocumentListener dl = new T1();
t1.addActionListener(new T1A());
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
cp.add(b1);
cp.add(b2);
cp.add(t1);
cp.add(t2);
cp.add(t3);
}
class T1 implements DocumentListener {
public void changedUpdate(DocumentEvent e){}
public void insertUpdate(DocumentEvent e){
t2.setText(t1.getText());
t3.setText("Text: "+ t1.getText());
}
public void removeUpdate(DocumentEvent e){
t2.setText(t1.getText());
}
}
class T1A implements ActionListener {
private int count = 0;
public void actionPerformed(ActionEvent e) {
t3.setText("t1 Action Event " + count++);
}
}
class B1 implements ActionListener {
public void actionPerformed(ActionEvent e) {
if(t1.getSelectedText() == null)
s = t1.getText();
else
s = t1.getSelectedText();
t1.setEditable(true);
}
}
class B2 implements ActionListener {
public void actionPerformed(ActionEvent e) {
ucd.setUpperCase(false);
t1.setText("Inserted by Button 2: " + s);
ucd.setUpperCase(true);
t1.setEditable(false);
}
}
public static void main(String[] args) {
Console.run(new TextFields(), 375, 125);
}
}
class UpperCaseDocument extends PlainDocument {
boolean upperCase = true;
public void setUpperCase(boolean flag) {
upperCase = flag;
}
public void insertString(int offset,
String string, AttributeSet attributeSet)
throws BadLocationException {
if(upperCase)
string = string.toUpperCase();
super.insertString(offset,
string, attributeSet);
}
} ///:~
Le JTextField t3 est inclus pour servir d'emplacement pour
signaler lorsque l'action listener du JTextField t1 est lancé.On verra
que l'action listener d'un JTextField n'est lancé que lorsqu'on appuie sur la
touche enter.
Le JTextField t1 a plusieurs listeners attachés.
le listener T1 est un Document Listener qui répond à tout changement dans
le document (le contenu du JTextField, dans ce cas). Il copie automatiquement tout
le texte de t1 dans t2. De plus, le document t1
est positionné à une classe dérivée de PlainDocument, appelée
UpperCaseDocument, qui force tous les caractères en majuscules. Il détecte
automatiquement les retours en arrière [backspaces]et effectue l'effacement, tout en
ajustant le curseur et gérant tout de la manière attendue.
Bordures
JComponent possède une méthode appelée
setBorder(), qui permet de placer différentes bordures intéressantes sur
tout composant visible. L'exemple suivant montre certaines des bordures existantes, en utilisant la
méthode showBorder() qui crée un JPanel et lui attache une
bordure à chaque fois. Il utilise aussi RTTI pour trouver le nom de la bordure qu'on utilise (en
enlevant l'information du chemin), et met ensuite le nom dans un JLabel au milieu
du panneau :
//: c13:Borders.java
// Diverses bordures Swing.
// <applet code=Borders
// width=500 height=300></applet>
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.border.*;
import com.bruceeckel.swing.*;
public class Borders extends JApplet {
static JPanel showBorder(Border b) {
JPanel jp = new JPanel();
jp.setLayout(new BorderLayout());
String nm = b.getClass().toString();
nm = nm.substring(nm.lastIndexOf('.') + 1);
jp.add(new JLabel(nm, JLabel.CENTER),
BorderLayout.CENTER);
jp.setBorder(b);
return jp;
}
public void init() {
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
cp.setLayout(new GridLayout(2,4));
cp.add(showBorder(new TitledBorder("Title")));
cp.add(showBorder(new EtchedBorder()));
cp.add(showBorder(new LineBorder(Color.blue)));
cp.add(showBorder(
new MatteBorder(5,5,30,30,Color.green)));
cp.add(showBorder(
new BevelBorder(BevelBorder.RAISED)));
cp.add(showBorder(
new SoftBevelBorder(BevelBorder.LOWERED)));
cp.add(showBorder(new CompoundBorder(
new EtchedBorder(),
new LineBorder(Color.red))));
}
public static void main(String[] args) {
Console.run(new Borders(), 500, 300);
}
} ///:~
On peut également créer ses propres bordures et les placer dans des
boutons, labels, et cetera, tout ce qui est dérivé de JComponent.
JScrollPanes
La plupart du temps on laissera le JScrollPane tel quel,
mais on peut aussi contrôler quelles barres de défilement sont autorisées, verticales,
horizontales, les deux ou ni l'une ni l'autre :
//: c13:JScrollPanes.java
// Contrôle des scrollbars d'un JScrollPane.
// <applet code=JScrollPanes width=300 height=725>
// </applet>
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import javax.swing.border.*;
import com.bruceeckel.swing.*;
public class JScrollPanes extends JApplet {
JButton
b1 = new JButton("Text Area 1"),
b2 = new JButton("Text Area 2"),
b3 = new JButton("Replace Text"),
b4 = new JButton("Insert Text");
JTextArea
t1 = new JTextArea("t1", 1, 20),
t2 = new JTextArea("t2", 4, 20),
t3 = new JTextArea("t3", 1, 20),
t4 = new JTextArea("t4", 10, 10),
t5 = new JTextArea("t5", 4, 20),
t6 = new JTextArea("t6", 10, 10);
JScrollPane
sp3 = new JScrollPane(t3,
JScrollPane.VERTICAL_SCROLLBAR_NEVER,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER),
sp4 = new JScrollPane(t4,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_NEVER),
sp5 = new JScrollPane(t5,
JScrollPane.VERTICAL_SCROLLBAR_NEVER,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS),
sp6 = new JScrollPane(t6,
JScrollPane.VERTICAL_SCROLLBAR_ALWAYS,
JScrollPane.HORIZONTAL_SCROLLBAR_ALWAYS);
class B1L implements ActionListener {
public void actionPerformed(ActionEvent e) {
t5.append(t1.getText() + "\n");
}
}
class B2L implements ActionListener {
public void actionPerformed(ActionEvent e) {
t2.setText("Inserted by Button 2");
t2.append(": " + t1.getText());
t5.append(t2.getText() + "\n");
}
}
class B3L implements ActionListener {
public void actionPerformed(ActionEvent e) {
String s = " Replacement ";
t2.replaceRange(s, 3, 3 + s.length());
}
}
class B4L implements ActionListener {
public void actionPerformed(ActionEvent e) {
t2.insert(" Inserted ", 10);
}
}
public void init() {
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
// Création de Borders pour les composants:
Border brd = BorderFactory.createMatteBorder(
1, 1, 1, 1, Color.black);
t1.setBorder(brd);
t2.setBorder(brd);
sp3.setBorder(brd);
sp4.setBorder(brd);
sp5.setBorder(brd);
sp6.setBorder(brd);
// Initialisation des listeners et ajout des composants:
b1.addActionListener(new B1L());
cp.add(b1);
cp.add(t1);
b2.addActionListener(new B2L());
cp.add(b2);
cp.add(t2);
b3.addActionListener(new B3L());
cp.add(b3);
b4.addActionListener(new B4L());
cp.add(b4);
cp.add(sp3);
cp.add(sp4);
cp.add(sp5);
cp.add(sp6);
}
public static void main(String[] args) {
Console.run(new JScrollPanes(), 300, 725);
}
} ///:~
L'utilisation des différents arguments du constructeur de
JScrollPane contrôle la présence des scrollbars. Cet exemple est également un peu
"habillé" à l'aide de bordures.
Un mini-éditeur
Le contrôle JTextPane fournit un support important pour
l'édition de texte, sans grand effort. L'exemple suivant en fait une utilisation très simple, en
ignorant le plus gros des fonctionnalités de la classe :
//: c13:TextPane.java
// Le contrôle JTextPane est un petit éditeur de texte.
// <applet code=TextPane width=475 height=425>
// </applet>
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import com.bruceeckel.swing.*;
import com.bruceeckel.util.*;
public class TextPane extends JApplet {
JButton b = new JButton("Add Text");
JTextPane tp = new JTextPane();
static Generator sg =
new Arrays2.RandStringGenerator(7);
public void init() {
b.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e){
for(int i = 1; i tp.setText(tp.getText() +
sg.next() + "\n");
}
});
Container cp = getContentPane();
cp.add(new JScrollPane(tp));
cp.add(BorderLayout.SOUTH, b);
}
public static void main(String[] args) {
Console.run(new TextPane(), 475, 425);
}
} ///:~
Le bouton ajoute simplement au hasard du texte généré. Le but du
JTextPane est de permettre la modification de texte sur place, de sorte qu'on ne
trouvera pas de méthode append(). Dans ce cas-ci (il est admis qu'il s'agit d'un
piètre usage des capacités de JTextPane), le texte doit être saisi, modifié, et
replacé dans le panneau en utilisant setText().