5. Grafische interfaces
Hier laten we zien hoe je grafische interfaces kunt bouwen met JAVA. We bekijken eerst welke basisklassen we kunnen gebruiken om een grafische interface te bouwen. In eerste instantie gebruiken we geen tool voor automatische generatie. Vervolgens gebruiken we JBuilder, een ontwikkeltool van Borland/Inprise die het ontwikkelen van Java-toepassingen en met name het bouwen van grafische interfaces vergemakkelijkt.
5.1. De basisprincipes van grafische gebruikersinterfaces
5.1.1. Een eenvoudig venster
Laten we eens kijken naar de volgende code:
// geïmporteerde klassen
import javax.swing.*;
import java.awt.*;
// de formulierklasse
public class form1 extends JFrame {
// de constructor
public form1() {
// venstertitel
this.setTitle("Mon premier formulaire");
// afmetingen van het venster
this.setSize(new Dimension(300,100));
}//constructor
// testfunctie
public static void main(String[] args) {
// het formulier wordt weergegeven
new form1().setVisible(true);
}
}//klasse
Als je de bovenstaande code uitvoert, verschijnt het volgende venster:

Een grafische interface is doorgaans afgeleid van de basisklasse JFrame:
public class form1 extends JFrame {
De basisklasse JFrame definieert een basisvenster met knoppen voor sluiten, vergroten/verkleinen, een aanpasbare grootte, enzovoort, en beheert de gebeurtenissen op deze grafische objecten. Hier specificeren we de basisklasse door er een titel en de breedte (300 pixels) en hoogte (100 pixels) aan toe te wijzen. Dit gebeurt in de constructor:
// de constructor
public form1() {
// venstertitel
this.setTitle("Mon premier formulaire");
// afmetingen van het venster
this.setSize(new Dimension(300,100));
}//constructor
De titel van het venster wordt bepaald door de methode setTitle en de afmetingen ervan door de methode setSize. Deze methode accepteert als parameter een object Dimension(largeur,hauteur), waarbij largeur en hauteur de breedte en hoogte van het venster zijn, uitgedrukt in pixels.
De methode main start de grafische toepassing als volgt:
new form1().setVisible(true);
Vervolgens wordt een formulier van het type form1 aangemaakt (new form1()) en weergegeven (setVisible(true)), waarna de toepassing luistert naar gebeurtenissen die op het formulier plaatsvinden (muisklikken, muisbewegingen, ...) en zorgt ervoor dat de gebeurtenissen die het formulier ondersteunt, worden uitgevoerd. In dit geval ondersteunt ons formulier geen andere gebeurtenissen dan die welke worden ondersteund door de basisklasse JFrame (klikken op knoppen voor sluiten, vergroten/verkleinen, het venster vergroten of verkleinen, het venster verplaatsen, ...).
Wanneer we dit programma testen door het vanuit een DOS-venster te starten met:
om het bestand form1.class uit te voeren, merken we dat wanneer we het weergegeven venster sluiten, we de controle niet terugkrijgen in het DOS-venster, alsof het programma nog niet is voltooid. Dit is inderdaad het geval. Het programma wordt als volgt uitgevoerd:
- in eerste instantie wordt een eerste uitvoeringsthread gestart om de methode main uit te voeren
- wanneer deze het formulier aanmaakt en weergeeft, wordt een tweede thread aangemaakt om specifiek de gebeurtenissen met betrekking tot het formulier te beheren
- na deze aanmaak en in ons voorbeeld wordt de thread van de methode main beëindigd en blijft alleen de uitvoerthread van de grafische interface over.
- Wanneer het venster wordt gesloten, verdwijnt het, maar wordt de thread waarin het werd uitgevoerd niet onderbroken
- We zijn voorlopig genoodzaakt deze thread te stoppen door op Ctrl-C te drukken in het DOS-venster van waaruit het programma is gestart.
Laten we controleren of er twee afzonderlijke threads bestaan: één waarin de methode main wordt uitgevoerd, en één waarin het grafische venster wordt uitgevoerd:
// geïmporteerde klassen
import javax.swing.*;
import java.awt.*;
import java.io.*;
// de formulierklasse
public class form1 extends JFrame {
// de constructor
public form1() {
// venstertitel
this.setTitle("Mon premier formulaire");
// afmetingen van het venster
this.setSize(new Dimension(300,100));
}//constructor
// testfunctie
public static void main(String[] args) {
// opvolging
System.out.println("Début du thread main");
// het formulier wordt weergegeven
new form1().setVisible(true);
// opvolging
System.out.println("Fin du thread main");
}//hoofdprocedure
}//klasse
De uitvoering levert de volgende resultaten op:

We zien dat de thread main is beëindigd, terwijl het venster nog steeds wordt weergegeven. Het sluiten van het venster beëindigt de thread waarin het werd uitgevoerd niet. Om deze thread te stoppen, drukken we opnieuw op Ctrl-C in het DOS-venster.
Om dit voorbeeld af te ronden, noteren we de geïmporteerde pakketten:
- javax.swing voor de klasse JFrame
- java.awt voor de klasse Dimension
5.1.2. Een gebeurtenis afhandelen
In het vorige voorbeeld zouden we het sluiten van het venster zelf moeten afhandelen, zodat de toepassing wordt gestopt wanneer dit gebeurt, wat op dit moment nog niet het geval is. Hiervoor moeten we een object maken dat ‘luistert’ naar de gebeurtenissen die zich in het venster voordoen en de gebeurtenis ‘sluiten van het venster’ detecteert. Dit object noemen we een ‘listener’ of gebeurtenisverwerker. Er bestaan verschillende soorten verwerkers voor de verschillende gebeurtenissen die zich kunnen voordoen op de componenten van een grafische gebruikersinterface. Voor de component JFrame heet de listener WindowListener en is het een interface die de volgende methoden definieert (zie Java-documentatie)
Methodenoverzicht | ||
void | windowActivated(WindowEvent e) Het venster wordt het actieve venster | |
void | windowClosed(WindowEvent e) Het venster is gesloten | |
void | windowClosing(WindowEvent e) De gebruiker of het programma heeft gevraagd het venster te sluiten | |
void | windowDeactivated(WindowEvent e) Het venster is niet langer het actieve venster | |
void | windowDeiconified(WindowEvent e) Het venster gaat van de geminimaliseerde toestand naar de normale toestand | |
void | windowIconified(WindowEvent e) Het venster gaat van de normale toestand naar de geminimaliseerde toestand | |
void | windowOpened(WindowEvent e) Het venster wordt voor het eerst zichtbaar | |
Er zijn dus zeven gebeurtenissen die kunnen worden afgehandeld. De handlers ontvangen allemaal als parameter een object van het type WindowEvent, dat we voorlopig buiten beschouwing laten. De gebeurtenis die ons hier interesseert, is het sluiten van het venster, een gebeurtenis die moet worden afgehandeld door de methode windowClosing. Om deze gebeurtenis af te handelen, kunnen we een object van het type Windowlistener aanmaken met behulp van een anonieme klasse, op de volgende manier:
// een gebeurtenisbeheerder aanmaken
WindowListener win=new WindowListener(){
public void windowActivated(WindowEvent e){}
public void windowClosed(WindowEvent e){}
public void windowClosing(WindowEvent e){System.exit(0);}
public void windowDeactivated(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
public void windowIconified(WindowEvent e){}
public void windowOpened(WindowEvent e){}
};//win-definitie
Onze gebeurtenisbehandelaar die de interface WindowListener implementeert, moet de zeven methoden van deze interface definiëren. Aangezien we alleen het sluiten van het venster willen afhandelen, schrijven we alleen code voor de methode windowClosing. Wanneer de andere gebeurtenissen plaatsvinden, krijgen we hiervan een melding, maar ondernemen we geen actie. Wat doen we wanneer we een melding krijgen dat het venster wordt gesloten (windowClosing)? We stoppen de applicatie:
public void windowClosing(WindowEvent e){System.exit(0);}
We hebben hier een object dat de gebeurtenissen van een venster in het algemeen kan afhandelen. Hoe koppelen we dit aan een specifiek venster? De klasse JFrame heeft een methode addWindowListener(WindowListener win) waarmee een „venster”-gebeurtenishandler aan een bepaald venster kan worden gekoppeld. Dus hier, in de constructor van het venster, schrijven we:
// aanmaken van een gebeurtenisbeheerder
WindowListener win=new WindowListener(){
public void windowActivated(WindowEvent e){}
public void windowClosed(WindowEvent e){}
public void windowClosing(WindowEvent e){System.exit(0);}
public void windowDeactivated(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
public void windowIconified(WindowEvent e){}
public void windowOpened(WindowEvent e){}
};//definitie win
// deze gebeurtenisverwerker zal de gebeurtenissen van het huidige venster beheren
this.addWindowListener(win);
Het volledige programma is als volgt:
// geïmporteerde klassen
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
// de formulierklasse
public class form2 extends JFrame {
// de constructor
public form2() {
// venstertitel
this.setTitle("Mon premier formulaire");
// afmetingen van het venster
this.setSize(new Dimension(300,100));
// aanmaken van een gebeurtenishandler
WindowListener win=new WindowListener(){
public void windowActivated(WindowEvent e){}
public void windowClosed(WindowEvent e){}
public void windowClosing(WindowEvent e){System.exit(0);}
public void windowDeactivated(WindowEvent e){}
public void windowDeiconified(WindowEvent e){}
public void windowIconified(WindowEvent e){}
public void windowOpened(WindowEvent e){}
};//win-definitie
// deze gebeurtenishandler zal de gebeurtenissen van het huidige venster afhandelen
this.addWindowListener(win);
}//constructor
// testfunctie
public static void main(String[] args) {
// het formulier wordt weergegeven
new form2().setVisible(true);
}//main
}//klasse
Het pakket java.awt.event bevat de interface WindowListener. Wanneer men dit programma uitvoert en het venster dat verscheen sluit, ziet men in het DOS-venster waarin het programma werd gestart dat het programma is beëindigd, wat voorheen niet het geval was.
In ons programma is het aanmaken van het object dat de venstergebeurtenissen beheert enigszins omslachtig, aangezien we genoodzaakt zijn methoden te definiëren, zelfs voor gebeurtenissen die we niet willen afhandelen. In dit geval kunnen we, in plaats van de interface WindowListener te gebruiken, de klasse WindowAdapter gebruiken. Deze implementeert de interface WindowListener, met zeven lege methoden. Door de klasse WindowAdapter af te leiden en alleen de methoden te herdefiniëren die voor ons van belang zijn, komen we tot hetzelfde resultaat als met de interface WindowListener, maar zonder dat we de methoden hoeven te definiëren die voor ons niet van belang zijn. De volgorde
- definitie van de gebeurtenishandler
- koppeling van de handler aan het venster
kan in ons voorbeeld als volgt worden uitgevoerd:
// een gebeurtenisverwerker aanmaken
WindowAdapter win=new WindowAdapter(){
public void windowClosing(WindowEvent e){System.exit(0);}
};//win-definitie
// deze gebeurtenishandler zal de gebeurtenissen van het huidige venster beheren
this.addWindowListener(win);
We gebruiken hier een anonieme klasse die is afgeleid van de klasse WindowAdapter en de methode windowClosing herdefinieert. Het programma ziet er dan als volgt uit:
// geïmporteerde klassen
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
// de formulierklasse
public class form2 extends JFrame {
// de constructor
public form2() {
// venstertitel
this.setTitle("Mon premier formulaire");
// afmetingen van het venster
this.setSize(new Dimension(300,100));
// aanmaken van een gebeurtenishandler
WindowAdapter win=new WindowAdapter(){
public void windowClosing(WindowEvent e){System.exit(0);}
};//Win-definitie
// deze gebeurtenishandler zal de gebeurtenissen van het huidige venster afhandelen
this.addWindowListener(win); }//constructor
// testfunctie
public static void main(String[] args) {
// het formulier wordt weergegeven
new form2().setVisible(true);
}//main
}//klasse
Dit programma levert dezelfde resultaten op als het vorige, maar is eenvoudiger te schrijven.
5.1.3. Een formulier met een knop
Laten we nu een knop aan ons venster toevoegen:
// geïmporteerde klassen
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
// de formulierklasse
public class form3 extends JFrame {
// een knop
JButton btnTest=null;
Container conteneur=null;
// de constructor
public form3() {
// venstertitel
this.setTitle("Formulaire avec bouton");
// afmetingen van het venster
this.setSize(new Dimension(300,100));
// een gebeurtenishandler aanmaken
WindowAdapter win=new WindowAdapter(){
public void windowClosing(WindowEvent e){System.exit(0);}
};//win-definitie
// deze gebeurtenishandler zal de gebeurtenissen van het huidige venster beheren
this.addWindowListener(win);
// we halen de container van het venster op
conteneur=this.getContentPane();
// we kiezen een opmaakbeheerder voor de componenten in deze container
conteneur.setLayout(new FlowLayout());
// we maken een knop aan
btnTest=new JButton();
// we stellen de tekst van de knop in
btnTest.setText("Test");
// de knop wordt aan de container toegevoegd
conteneur.add(btnTest);
}//constructor
// testfunctie
public static void main(String[] args) {
// het formulier wordt weergegeven
new form3().setVisible(true);
}//main
}//klasse
Een venster JFrame heeft een container waarin grafische componenten (knoppen, selectievakjes, vervolgkeuzelijsten, ...) kunnen worden geplaatst. Deze container is beschikbaar via de methode getContentPane van de klasse JFrame:
Container conteneur=null;
..........
// de container van het venster wordt opgehaald
conteneur=this.getContentPane();
Elke component wordt in de container geplaatst via de methode add van de klasse Container. Om component C in het voorgaande object conteneur te plaatsen, schrijft men dus:
Waar wordt deze component in de container geplaatst? Er bestaan verschillende componentlay-outmanagers met de naam XXXLayout, waarbij XXX bijvoorbeeld gelijk is aan Border, Flow, ... Elke lay-outmanager heeft zijn eigen kenmerken. De lay-outmanager FlowLayout plaatst de componenten bijvoorbeeld in rijen, beginnend bovenaan het formulier. Wanneer een rij is gevuld, worden de componenten op de volgende rij geplaatst. Om een opmaakmanager aan een venster JFrame te koppelen, gebruikt men de methode setLayout van de klasse JFrame in de vorm:
In ons voorbeeld hebben we dus, om een handler van het type FlowLayout aan het venster te koppelen, het volgende geschreven:
// er wordt een opmaakbeheerder voor de componenten in deze container gekozen
conteneur.setLayout(new FlowLayout());
Het is ook mogelijk om geen lay-outmanager te gebruiken en het volgende te schrijven:
In dat geval moeten we de exacte coördinaten van de component in de container opgeven in de vorm (x,y,breedte,hoogte), waarbij (x,y) de coördinaten zijn van de linkerbovenhoek van de component in de container. Dit is de methode die we hierna het vaakst zullen gebruiken.
We weten nu hoe de componenten in de container (add) worden geplaatst en waar (setLayout). Nu moeten we nog weten welke
componenten die in een container kunnen worden geplaatst. Hier plaatsen we een knop die wordt gemodelleerd door de klasse javax.swing.JButton:
JButton btnTest=null;
..........
// we maken een knop aan
btnTest=new JButton();
// we stellen de tekst van de knop in
btnTest.setText("Test");
// de knop wordt aan de container toegevoegd
conteneur.add(btnTest);
Wanneer we dit programma testen, verschijnt het volgende venster:

Als je de afmetingen van het bovenstaande formulier aanpast, wordt automatisch de lay-outmanager van de container aangeroepen om de componenten opnieuw te plaatsen:

Dat is het belangrijkste voordeel van lay-outmanagers: ze zorgen ervoor dat de componenten een consistente lay-out behouden, ook al verandert de grootte van de container. Laten we de lay-outmanager null gebruiken om het verschil te zien. De knop wordt nu met de volgende instructies in de container geplaatst:
// we kiezen een opmaakbeheerder voor de componenten in deze container
conteneur.setLayout(null);
// we maken een knop aan
btnTest=new JButton();
// de tekst ervan instellen
btnTest.setText("Test");
// de positie en afmetingen worden vastgelegd
btnTest.setBounds(10,20,100,20);
// de knop wordt aan de container toegevoegd
conteneur.add(btnTest);
Hier plaatsen we de knop expliciet op het punt (10,20) van het formulier en stellen we de afmetingen in op 100 pixels breed en 20 pixels hoog. Het nieuwe venster ziet er als volgt uit:

Als we het venster vergroten of verkleinen, blijft de knop op dezelfde plaats staan.

Als we op de knop Test klikken, gebeurt er niets. We hebben namelijk nog geen gebeurtenishandler aan de knop gekoppeld. Om te weten welke soorten gebeurtenishandlers er voor een bepaalde component beschikbaar zijn, kun je in de definitie van de klasse zoeken naar methoden die het mogelijk maken om een gebeurtenishandler aan de component te koppelen. De klasse javax.swing.JButton is afgeleid van de klasse javax.swing.AbstractButton, waarin de volgende methoden te vinden zijn:
Methodenoverzicht | ||
void | addActionListener(ActionListener l) | |
void | addChangeListener(ChangeListener l) | |
void | addItemListener(ItemListener l) | |
Hier moet je de documentatie raadplegen om te weten welke gebeurtenisverwerker de klik op de knop afhandelt. Dat is de interface ActionListener. Deze definieert slechts één methode:
Methodenoverzicht | ||
void | actionPerformed(ActionEvent e) | |
De methode ontvangt een parameter ActionEvent die we voorlopig buiten beschouwing laten. Om de klik op de knop btntest in ons programma af te handelen, koppelen we er eerst een gebeurtenishandler aan:
btnTest.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt){
btnTest_clic(evt);
}
}//anonieme klasse
);//gebeurtenisverwerker
Hier verwijst de methode actionPerformed naar de methode btnTest_clic, die we als volgt definiëren:
public void btnTest_clic(ActionEvent evt){
// console-logboek
System.out.println("clic sur bouton");
}//btnTest_click
Telkens wanneer de gebruiker op de knop Test klikt, wordt er een bericht naar de console geschreven. Dit blijkt uit de volgende uitvoering:

Het volledige programma is als volgt:
// geïmporteerde klassen
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
// de formulierklasse
public class form4 extends JFrame {
// een knop
JButton btnTest=null;
Container conteneur=null;
// de constructor
public form4() {
// venstertitel
this.setTitle("Formulaire avec bouton");
// afmetingen van het venster
this.setSize(new Dimension(300,100));
// een gebeurtenishandler aanmaken
WindowAdapter win=new WindowAdapter(){
public void windowClosing(WindowEvent e){System.exit(0);}
};//win-definitie
// deze gebeurtenishandler zal de gebeurtenissen van het huidige venster beheren
this.addWindowListener(win);
// we halen de container van het venster op
conteneur=this.getContentPane();
// we kiezen een opmaakbeheerder voor de componenten in deze container
conteneur.setLayout(null);
// we maken een knop aan
btnTest=new JButton();
// we stellen de tekst van de knop in
btnTest.setText("Test");
// de positie en afmetingen ervan worden vastgelegd
btnTest.setBounds(10,20,100,20);
// er wordt een gebeurtenishandler aan gekoppeld
btnTest.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt){
btnTest_clic(evt);
}
}//anonieme klasse
);//gebeurtenishandler
// de knop wordt aan de container toegevoegd
conteneur.add(btnTest);
}//constructor
public void btnTest_clic(ActionEvent evt){
// console-tracking
System.out.println("clic sur bouton");
}//btnTest_click
// testfunctie
public static void main(String[] args) {
// het formulier wordt weergegeven
new form4().setVisible(true);
}//hoofdfunctie
}//klasse
5.1.4. De gebeurtenisverwerkers
De belangrijkste Swing-componenten die we zullen bespreken zijn vensters (JFrame), knoppen (JButton), selectievakjes (JCheckBox), keuzerondjes (JButtonRadio), vervolgkeuzelijsten (JComboBox), lijsten (JList), schuifregelaars (JScrollBar), labels (JLabel), invoervelden met één regel (JTextField) of met meerdere regels (JTextArea), menu's (JMenuBar), menu-items (JMenuItem).
De volgende tabellen geven een overzicht van enkele gebeurtenisbeheerders en de gebeurtenissen waarmee ze zijn gekoppeld.
Handler | Component(en) | Registratiemethode | Gebeurtenis |
ActionListener | JButton, JCheckbox, JButtonRadio, JMenuItem | public void addActionListener(ActionListener) | klik op de knop, het selectievakje, het keuzerondje of het menu-item |
JTextField | |||
ItemListener | JComboBox, JList | public void addItemListener(ItemListener) | Het geselecteerde element is gewijzigd |
InputMethodListener | JTextField, JTextArea | public void addMethodInputListener(InputMethodListener) | de tekst in het invoerveld is gewijzigd of de invoercursor is verplaatst |
CaretListener | JTextField, JTextArea | public void addcaretListener(CaretListener) | De invoercursor is van positie veranderd |
AdjustmentListener | JScrollBar | public void addAdjustmentListener(AdjustmentListener) | de waarde van de regelaar is gewijzigd |
MouseMotionListener | public void addMouseMotionListener(MouseMotionListener) | de muis is bewogen | |
WindowListener | JFrame | public void addWindowlistener(WindowListener) | venstergebeurtenis |
MouseListener | public void addMouselistener(MouseListener) | muisgebeurtenissen (klik, binnenkomen/verlaten van het gebied van een component, knop ingedrukt, loslaten) | |
FocusListener | public void addFocuslistener(FocusListener) | focusgebeurtenis (verkregen, verloren) | |
KeyListener | public void addKeylistener(KeyListener) | toetsenbordgebeurtenis (toets ingedrukt, ingedrukt gehouden, losgelaten) |
Component | Methode voor het registreren van gebeurtenishandlers |
JButton | public void addActionListener(ActionListener) |
JCheckbox | public void addItemListener(ItemListener) |
JCheckboxMenuItem | public void addItemListener(ItemListener) |
JComboBox | public void addItemListener(ItemListener) public void addActionListener(ActionListener) |
Container | public void addContainerListener(ContainerListener) |
JComponent | public void addComponentListener(ComponentListener) public void addFocusListener(FocusListener) public void addKeyListener(KeyListener) public void addMouseListener(MouseListener) public void addMouseMotionListener(MouseMotionListener) |
JFrame | public void addWindowlistener(WindowListener) |
JList | public void addItemListener(ItemListener) |
JMenuItem | public void addActionListener(ActionListener) |
JPanel | als Container |
JScrollPane | als container |
JScrollBar | public void addAdjustmentListener(AdjustmentListener) |
JTextComponent | public void addInputMethodListener(InputMethodListener) public void addCaretListener(CaretListener) |
JTextArea | zoals JTextComponent |
JTextField | zoals JTextComponent public void addActionListener(ActionListener) |
Alle componenten, behalve die van het type TextXXX, zijn afgeleid van de klasse JComponent en beschikken daarom ook over de methoden die bij deze klasse horen.
5.1.5. De methoden van de gebeurtenishandlers
De volgende tabel geeft een overzicht van de methoden die door de verschillende gebeurtenishandlers moeten worden geïmplementeerd.
Interface | Methoden |
ActionListener | public void actionPerformed(ActionEvent) |
AdjustmentListener | public void adjustmentValueChanged(AdjustmentEvent) |
ComponentListener | public void componentHidden(ComponentEvent) public void componentMoved(ComponentEvent) public void componentResized(ComponentEvent) public void componentShown(ComponentEvent) |
ContainerListener | public void componentAdded(ContainerEvent) public void componentRemoved(ContainerEvent) |
FocusListener | public void focusGained(FocusEvent) public void focusLost(FocusEvent) |
ItemListener | public void itemStateChanged(ItemEvent) |
KeyListener | public void keyPressed(KeyEvent) public void keyReleased(KeyEvent) public void keyTyped(KeyEvent) |
MouseListener | public void mouseClicked(MouseEvent) public void mouseEntered(MouseEvent) public void mouseExited(MouseEvent) public void mousePressed(MouseEvent) public void mouseReleased(MouseEvent) |
MouseMotionListener | public void mouseDragged(MouseEvent) public void mouseMoved(MouseEvent) |
TextListener | public void textValueChanged(TextEvent) |
InputmethodListener | public void InputMethodTextChanged(InputMethodEvent) public void caretPositionChanged(InputMethodEvent) |
CaretLisetner | public void caretUpdate(CaretEvent) |
WindowListener | public void windowActivated(WindowEvent) public void windowClosed(WindowEvent) public void windowClosing(WindowEvent) public void windowDeactivated(WindowEvent) public void windowDeiconified(WindowEvent) public void windowIconified(WindowEvent) public void windowOpened(WindowEvent) |
5.1.6. De adapterklassen
Zoals we bij de interface WindowListener hebben gezien, bestaan er klassen met de naam XXXAdapter die de interfaces XXXListener implementeren met lege methoden. Een gebeurtenishandler die is afgeleid van een klasse XXXAdapter kan dan slechts een deel van de methoden van de interface XXXListener implementeren, namelijk die methoden die de toepassing nodig heeft.
Stel dat we muisklikken op een Frame-component f1 willen afhandelen. We zouden hieraan een gebeurtenishandler kunnen koppelen via:
en het volgende te schrijven:
public class gestionnaireSouris implements MouseListener{
// de 5 methoden van de interface worden geschreven MouseListener
// mouseClicked, ..., mouseReleased)
}// einde klasse
Aangezien we alleen muisklikken willen verwerken, is het echter beter om het volgende te schrijven:
public class gestionnaireSouris extends MouseAdapter{
// we schrijven slechts één methode, namelijk die welke de muisklikken afhandelt
public void mouseClicked(MouseEvent evt){
…
}
}// einde klasse
De volgende tabel geeft de adapterklassen van de verschillende gebeurtenisverwerkers weer:
Gebeurtenishandler | Adapter |
ComponentListener | ComponentAdapter |
ContainerListener | ContainerAdapter |
FocusListener | FocusAdapter |
KeyListener | KeyAdapter |
MouseListener | MouseAdapter |
MouseMotionListener | MouseMotionAdapter |
WindowListener | WindowAdapter |
5.1.7. Conclusie
We hebben zojuist de basisbegrippen van het maken van grafische gebruikersinterfaces in Java besproken:
- het maken van een venster
- het maken van componenten
- het koppelen van componenten aan het venster met behulp van een lay-outhandler
- het koppelen van gebeurtenishandlers aan de componenten
In plaats van grafische interfaces ‘met de hand’ te bouwen, zoals zojuist is gedaan, gaan we nu JBuilder gebruiken, een Java-ontwikkeltool van Borland/Inprise in versie 4, en supérieure.Nous. We zullen gebruikmaken van de componenten uit de bibliotheek java.swing, die momenteel wordt aanbevolen door Sun, de maker van Java.
5.2. Een grafische interface bouwen met JBuilder
5.2.1. Ons eerste JBuilder-project
Om vertrouwd te raken met JBuilder, gaan we een heel eenvoudige toepassing bouwen: een leeg venster.
- Start JBuilder op en kies de optie Bestand/Nieuw project. De eerste pagina van een wizard verschijnt dan:

- Vul de volgende velden in:
Naam van het project | Start Hierdoor wordt een projectbestand début.jpr aangemaakt in de map die is opgegeven in het veld "Naam van de projectmap" |
Hoofdmap | Geef de map op waarin de map van het project dat u gaat aanmaken, zal worden aangemaakt. |
Naam van de projectmap | Geef de naam op van de map waarin alle projectbestanden zullen worden geplaatst. Deze map wordt aangemaakt in de map die is opgegeven in het veld "Hoofdmap" |
De bronbestanden (.java, .html, ...), de doelbestanden (.class, ...) en de back-upbestanden kunnen in verschillende mappen worden geplaatst. Als u de bijbehorende velden leeg laat, worden ze in dezelfde map als het project geplaatst.
Maak [suivant]
- Een scherm bevestigt de keuzes uit de vorige stap

Voer [suivant] in
- Een nieuw scherm vraagt u om uw project te specificeren:

Voer [terminer] in
- Controleer of de optie Voir/projet is aangevinkt. U zou de structuur van uw project in het linkervenster moeten zien.

- Laten we nu een grafische interface in dit project bouwen. Kies de optie Fichier/Nouveau/Application:

In het veld classe vult u de naam in van de klasse die aangemaakt gaat worden. Hier hebben we dezelfde naam gebruikt als die van het project.
Voer [suivant] in
- Het volgende scherm verschijnt:

Klasse | interfaceDébut Dit is de naam van de klasse die overeenkomt met het venster dat zal worden aangemaakt |
Titel | Dit is de tekst die in de titelbalk van het venster zal verschijnen |
Merk op dat we hierboven hebben aangegeven dat het venster bij het opstarten van de applicatie gecentreerd op het scherm moet worden weergegeven.
Maak [Terminer]
- Nu komt JBuilder goed van pas.
- Het genereert de .java-bronbestanden van de twee klassen waarvan we de namen hebben opgegeven: de applicatieklasse en die van de grafische interface. Deze twee bestanden verschijnen in de projectstructuur in het linkervenster

- Om de gegenereerde code voor beide klassen te bekijken, hoeft u alleen maar te dubbelklikken op het bijbehorende .java-bestand. We komen later terug op de gegenereerde code.
- Controleer of de optie Voir/Structure is aangevinkt. Hiermee kunt u de structuur van de momenteel geselecteerde klasse bekijken (dubbelklik op het .java-bestand). Hieronder ziet u bijvoorbeeld de structuur van de klasse début:

Hier zie je:
-
welke bibliotheken zijn geïmporteerd (imports)
-
dat er een constructor is: début()
-
dat er een statische methode is: main()
-
dat er een attribuut is: packFrame
Wat is het nut van toegang tot de structuur van een klasse?
-
je krijgt er een overzicht van. Dit is handig als je klasse complex is.
-
u kunt de code van een methode openen door erop te klikken in het structuurvenster van de klasse. Ook dit is handig als uw klasse honderden regels telt. U hoeft dan niet alle regels door te nemen om de code te vinden die u zoekt.
De door JBuilder gegenereerde code is al bruikbaar. Kies Uitvoeren/Project uitvoeren of F9 en je krijgt het gevraagde venster te zien:

Bovendien wordt het venster netjes gesloten wanneer je op de sluitknop klikt. We hebben zojuist onze eerste grafische gebruikersinterface gebouwd. We kunnen ons project opslaan via de optie Bestand/Projecten sluiten:

Door op Tous te drukken, worden alle projecten in het bovenstaande venster aangevinkt. OK sluit ze. Als we uit nieuwsgierigheid met Windows Verkenner naar de map van ons project gaan (die aan het begin van de projectconfiguratie aan de wizard is opgegeven), vinden we daar de volgende bestanden:

In ons voorbeeld hadden we aangegeven dat alle bestanden (bronbestanden .java, doelbestanden .class, back-upbestanden .jpr~) in dezelfde map moesten staan als het .jpr-project.
5.2.2. De bestanden die door JBuilder voor een grafische gebruikersinterface zijn gegenereerd
Laten we nu eens kijken welke .java-bronbestanden JBuilder heeft gegenereerd. Het is belangrijk om te weten hoe je de gegenereerde code moet interpreteren, aangezien we meestal code moeten toevoegen aan wat er is gegenereerd. Laten we beginnen met ons project op te halen: Bestand/Project openen en selecteer het project début.jpr. We zien het project dat we eerder hebben opgebouwd.
5.2.2.1. De hoofdklasse
Laten we de klasse début.java bekijken door op de naam te dubbelklikken in het venster met de lijst van projectbestanden. We zien de volgende code:
import javax.swing.UIManager;
import java.awt.*;
public class début {
boolean packFrame = false;
/**De applicatie bouwen*/
public début() {
interfaceDébut frame = new interfaceDébut();
//Vensterelementen met vooraf gedefinieerde afmetingen valideren
//Frames met voorkeursafmetingen samenvoegen – bijv. op basis van hun indeling
if (packFrame) {
frame.pack();
}
else {
frame.validate();
}
//Het venster centreren
Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
Dimension frameSize = frame.getSize();
if (frameSize.height > screenSize.height) {
frameSize.height = screenSize.height;
}
if (frameSize.width > screenSize.width) {
frameSize.width = screenSize.width;
}
frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
frame.setVisible(true);
}
/**Hoofdmethode*/
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(Exception e) {
e.printStackTrace();
}
new début();
}
}
Laten we de gegenereerde code eens bekijken:
- de functie main bepaalt het uiterlijk van het venster (setLookAndFeel) en maakt een instantie aan van de klasse début.
- Vervolgens wordt de constructor début() uitgevoerd. Deze maakt een instantie frame van de vensterklasse aan (new interfaceDébut()). Deze wordt geconstrueerd, maar niet weergegeven.
- Het venster wordt vervolgens op maat gemaakt op basis van de beschikbare informatie voor elk van de venstercomponenten (frame.validate). Het begint dan aan zijn eigen bestaan door zich weer te geven en te reageren op de acties van de gebruiker.
- Het venster wordt gecentreerd op het scherm, omdat dit was opgegeven tijdens de configuratie van het venster met de wizard.
Laten we eens kijken wat het resultaat zou zijn als we de code début.java zouden terugbrengen tot het strikt noodzakelijke, zoals we aan het begin van dit hoofdstuk hebben gedaan. Laten we een nieuwe klasse aanmaken. Kies de optie Bestand/Nieuwe klasse:

Geef de nieuwe klasse de naam début2 en maak [Terminer] aan. Er verschijnt een nieuw bestand in het project:

Het bestand début2.java is teruggebracht tot de meest eenvoudige vorm:
Laten we de klasse als volgt aanvullen:
public class début2 {
// hoofdfunctie
public static void main(String args[]){
// maakt het venster aan
new interfaceDébut().show(); // of new interfaceDébut.setVisible(true);
}//main
}//klasse begin2
De functie main maakt een instantie van het venster interfaceDébut aan en geeft deze weer (show). Voordat we ons project uitvoeren, moeten we erop wijzen dat de klasse die de uit te voeren functie main bevat, nu de klasse début2 is. Klik met de rechtermuisknop op het project début.jpr en kies de optie propriétés en vervolgens het tabblad Exécution:
21

Hier wordt aangegeven dat de hoofdklasse début is (1). Druk op de knop (2) om een andere hoofdklasse te kiezen:

Kies début2 en maak er [OK] van.

Voer [OK] in om deze keuze te bevestigen en vraag vervolgens om het project uit te voeren via Uitvoeren/Project uitvoeren of F9. U krijgt hetzelfde venster te zien als bij de klasse début, behalve dat het niet gecentreerd is, aangezien dit hier niet is gevraagd. Vervolgens zullen we de door JBuilder gegenereerde hoofdklasse niet meer laten zien, omdat deze altijd hetzelfde doet: een venster aanmaken. Vanaf nu zullen we ons concentreren op de klasse van dit venster.
5.2.2.2. De vensterklasse
Laten we nu eens kijken naar de code die is gegenereerd voor de klasse interfaceDébut:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class interfaceDébut extends JFrame {
JPanel contentPane;
BorderLayout borderLayout1 = new BorderLayout();
/**Het frame opbouwen*/
public interfaceDébut() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**De component initialiseren*/
private void jbInit() throws Exception {
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(borderLayout1);
this.setSize(new Dimension(400, 300));
this.setTitle("Ma première interface graphique avec Jbuilder");
}
/**Vervangen, zodat we kunnen afsluiten wanneer het venster wordt gesloten*/
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
}
5.2.2.2.1. De geïmporteerde bibliotheken
Het gaat om de bibliotheken java.awt, java.awt.event en javax.swing. De eerste twee waren de enige die beschikbaar waren om grafische interfaces te bouwen met de eerste versies van Java. De bibliotheek javax.swing is recenter. Hier is deze nodig voor het venster van het type JFrame dat hier wordt gebruikt.
5.2.2.2.2. De attributen
JPanel is een containertype waarin componenten kunnen worden geplaatst. BorderLayout is een van de beschikbare lay-outmanagers om de componenten in de container te plaatsen. In al onze voorbeelden zullen we geen opmaakmanager gebruiken en zullen we de componenten zelf op een specifieke plek in de container plaatsen. Hiervoor gebruiken we de opmaakmanager null.
5.2.2.2.3. De vensterbouwer
/**Het frame opbouwen*/
public interfaceDébut() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**De component initialiseren*/
private void jbInit() throws Exception {
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(borderLayout1);
this.setSize(new Dimension(400, 300));
this.setTitle("Ma première interface graphique avec Jbuilder");
}
- De maker geeft eerst aan dat hij de gebeurtenissen in het venster (enableEvents) gaat afhandelen, en roept vervolgens de methode jbInit aan.
- De container (JPanel) van het venster (JFrame) wordt opgehaald (getContentPane)
- De opmaakmanager wordt ingesteld (setLayout)
- De grootte van het venster is vastgelegd (setSize)
- De titel van het venster is vastgelegd (setTitle)
5.2.2.2.4. De gebeurtenisbeheerder
/**Vervangen, zodat we kunnen afsluiten wanneer het venster wordt gesloten*/
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
De ontwikkelaar had aangegeven dat de klasse de gebeurtenissen van het venster zou verwerken. Dit wordt gedaan door de methode processWindowEvent. Deze methode begint met het doorsturen van de ontvangen gebeurtenis WindowEvent naar de bovenliggende klasse (JFrame). Als dit de gebeurtenis WINDOW_CLOSING is, die wordt veroorzaakt door het klikken op de knop om het venster te sluiten, wordt de toepassing beëindigd.
5.2.2.2.5. Conclusie
De code van de vensterklasse verschilt van die in het voorbeeld aan het begin van dit hoofdstuk. Als we een andere tool voor het genereren van Java-code zouden gebruiken dan JBuilder, zouden we ongetwijfeld weer andere code krijgen. In de praktijk nemen we genoegen met de door JBuilder gegenereerde code voor het bouwen van het venster, zodat we ons uitsluitend kunnen concentreren op het schrijven van de gebeurtenishandlers voor de grafische gebruikersinterface.
5.2.3. Een grafische gebruikersinterface ontwerpen
5.2.3.1. Een voorbeeld
In het vorige voorbeeld hadden we geen componenten in het venster geplaatst. Laten we nu een venster bouwen met een knop, een label en een invoerveld:

De velden zijn als volgt:
nr. | naam | type | rol |
1 | lblSaisie | JLabel | een omschrijving |
2 | txtSaisie | JTextField | een invoerveld |
3 | cmdAfficher | JButton | om de inhoud van het invoerveld in een dialoogvenster weer te geven txtSaisie |
Ga te werk zoals bij het vorige project en bouw het project interface2.jpr, zonder voorlopig componenten in het venster te plaatsen.

Selecteer in het bovenstaande venster de klasse interface2.java. Rechts van dit venster bevindt zich een tabbladmap:

Het tabblad Source geeft toegang tot de broncode van de klasse interface2.java. Via het tabblad Conception kunt u het venster visueel opbouwen. Selecteer dit tabblad. U ziet nu de container van het venster, waarin de componenten zullen worden geplaatst die u erin neerzet. Deze is op dit moment leeg. In het linkervenster wordt de structuur van de klasse weergegeven:

this | staat voor het venster |
contentPane | de container waarin componenten worden geplaatst, evenals de manier waarop deze componenten in de container worden gerangschikt (standaard BorderLayout) |
borderLayout1 | een instantie van de opmaakbeheerder |
Selecteer het object this. Het eigenschappenvenster verschijnt dan aan de rechterkant:

Enkele van deze eigenschappen zijn het vermelden waard:
background | om de achtergrondkleur van het venster in te stellen |
foreground | om de kleur van de afbeeldingen in het venster in te stellen |
JMenuBar | om een menu aan het venster te koppelen |
title | om het venster een titel te geven |
resizable | om het type venster vast te stellen |
font | om het lettertype van de tekst in het venster in te stellen |
Terwijl het object this nog steeds is geselecteerd, kunt u de grootte van de op het scherm weergegeven container aanpassen door aan de verankeringspunten rondom de container te slepen:

We zijn nu klaar om componenten in de bovenstaande container te plaatsen. Maar eerst gaan we de opmaakmanager wijzigen. Selecteer het object contentPane in het structuurvenster:

Selecteer vervolgens in het eigenschappenvenster van dit object de eigenschap layout en kies uit de mogelijke waarden de waarde null:

Doordat er geen opmaakbeheerder is, kunnen we de componenten vrij in de container plaatsen. Het is nu tijd om deze te kiezen.
Wanneer het paneel Conception is geselecteerd, zijn de componenten beschikbaar in een map met tabbladen bovenaan het ontwerpvenster:

Om de grafische interface te bouwen, beschikken we over componenten swing (1) en componenten awt (2). We gaan hier de componenten swing gebruiken. Kies in de bovenstaande componentenbalk een JLabel-component (3), een JTextField-component (4) en een JButton-component (5) en plaats deze in de container van het ontwerpvenster.

Laten we nu elk van deze drie componenten aanpassen:
- het label (JLabel) jLabel1
Selecteer de component om het eigenschappenvenster te openen. Wijzig daarin de volgende eigenschappen: name: lblSaisie, text: Invoer
- het invoerveld (JTextField) jTextfield1
Selecteer de component om het eigenschappenvenster te openen. Wijzig daarin de volgende eigenschappen: name: txtSaisie, text: niets invoeren
- de knop (JButton): naam: cmdAfficher, tekst: Weergeven
We hebben nu het volgende venster:

en de volgende structuur:

We kunnen (F9) ons project uitvoeren om een eerste indruk te krijgen van het venster in actie:

Sluit het venster. Nu moeten we nog de procedure schrijven die wordt uitgevoerd wanneer er op de knop Afficher wordt geklikt. Selecteer de knop om het eigenschappenvenster te openen. Dit venster heeft twee tabbladen: propriétés en événements. Kies événements.

In de linkerkolom van het venster staan de mogelijke gebeurtenissen voor de knop vermeld. Een klik op een knop komt overeen met de gebeurtenis actionPerformed. De rechterkolom bevat de naam van de procedure die wordt aangeroepen wanneer de bijbehorende gebeurtenis plaatsvindt. Klik op de cel rechts van de gebeurtenis actionPerformed:

JBuilder genereert voor elke gebeurtenishandler een standaardnaam in de vorm nomComposant_nomEvénement, in dit geval cmdAfficher_actionPerformed. Je kunt de voorgestelde standaardnaam wissen en een andere invoeren. Om toegang te krijgen tot de code van de handler cmdAfficher_actionPerformed hoef je alleen maar op de naam hierboven te dubbelklikken. Je gaat dan automatisch naar het bronvenster van de klasse, waar het raamwerk van de code van de gebeurtenishandler is geselecteerd:
Nu hoeven we deze code alleen nog maar aan te vullen. Hier willen we een dialoogvenster weergeven met daarin de inhoud van het veld txtSaisie:
void cmdAfficher_actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(),
"Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
}
JOptionPane is een klasse uit de bibliotheek javax.swing. Hiermee kunnen berichten met een pictogram worden weergegeven of kan informatie aan de gebruiker worden gevraagd. Hier gebruiken we een statische methode van de klasse:

parentComponent | het ‘bovenliggende’ containerobject van het dialoogvenster: in dit geval this. |
bericht | een object dat moet worden weergegeven. Hier de inhoud van het invoerveld |
title | de titel van het dialoogvenster |
messageType | het type bericht dat moet worden weergegeven. Bepaalt het pictogram dat in het vakje naast het bericht wordt weergegeven. Mogelijke waarden: INFORMATION_MESSAGE, QUESTION_MESSAGE, ERROR_MESSAGE, WARNING_MESSAGE, PLAIN_MESSAGE |
Laten we onze applicatie (F9) uitvoeren:


5.2.3.2. De klassecode van het venster
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;
import javax.swing.event.*;
public class interface2 extends JFrame {
JPanel contentPane;
JLabel lblSaisie = new JLabel();
JTextField txtSaisie = new JTextField();
JButton cmdAfficher = new JButton();
/**Het frame opbouwen*/
public interface2() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**De component initialiseren*/
private void jbInit() throws Exception {
lblSaisie.setText("Saisie");
lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(null);
this.setSize(new Dimension(304, 129));
this.setTitle("Saisies & boutons - 1");
txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
cmdAfficher.setText("Afficher");
cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
cmdAfficher_actionPerformed(e);
}
});
contentPane.add(lblSaisie, null);
contentPane.add(txtSaisie, null);
contentPane.add(cmdAfficher, null);
}
/**Vervangen, zodat we kunnen afsluiten wanneer het venster wordt gesloten*/
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
void cmdAfficher_actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(), "Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
}
}
5.2.3.2.1. De attributen
JPanel contentPane;
JLabel lblSaisie = new JLabel();
JTextField txtSaisie = new JTextField();
JButton cmdAfficher = new JButton();
Er is een verpakking met onderdelen van het type JPanel en de drie onderdelen.
5.2.3.2.2. De fabrikant
/**Het frame opbouwen*/
public interface2() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**De component initialiseren*/
private void jbInit() throws Exception {
lblSaisie.setText("Saisie");
lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(null);
this.setSize(new Dimension(304, 129));
this.setTitle("Saisies & boutons - 1");
txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
cmdAfficher.setText("Afficher");
cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
cmdAfficher_actionPerformed(e);
}
});
contentPane.add(lblSaisie, null);
contentPane.add(txtSaisie, null);
contentPane.add(cmdAfficher, null);
}
De constructor interface2 lijkt op de constructor van de vorige grafische interface die we hebben bestudeerd. De verschillen zitten in de methode jbInit: de code voor het opbouwen van het venster hangt af van de componenten die erin zijn geplaatst. We kunnen de code van jbInit overnemen en er onze eigen opmerkingen aan toevoegen:
private void jbInit() throws Exception {
// het venster zelf (grootte, titel)
this.setSize(new Dimension(304, 129));
this.setTitle("Saisies & boutons - 1");
// de container voor de componenten
contentPane = (JPanel) this.getContentPane();
// geen opmaakbeheerder voor deze container
contentPane.setLayout(null);
// het label lblSaisie (tekst, positie, grootte)
lblSaisie.setText("Saisie");
lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
// het invoerveld (positie, grootte)
txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
// de knop Weergeven (tekst, positie, grootte)
cmdAfficher.setText("Afficher");
cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
// de gebeurtenisverwerker van de knop
cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
cmdAfficher_actionPerformed(e);
}
});
// de drie componenten aan de container toevoegen
contentPane.add(lblSaisie, null);
contentPane.add(txtSaisie, null);
contentPane.add(cmdAfficher, null);
}//jbInit
Twee opmerkingen:
- deze code had met de hand geschreven kunnen worden. Dit betekent dat men JBuilder niet nodig heeft om een grafische interface te bouwen.
- de manier waarop de gebeurtenishandler van de knop cmdAfficher is ingesteld. De gebeurtenishandler van de component cmdAfficher had kunnen worden gedeclareerd via cmdAfficher.addActionListener(new handler()) waarbij gestionnaire een klasse zou zijn met een openbare methode actionPerformed die verantwoordelijk is voor het afhandelen van de klik op de knop Afficher. Hier gebruikt JBuilder als handler een instantie van een anonieme klasse:
new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
cmdAfficher_actionPerformed(e);
}
Er wordt een nieuwe instantie van de interface ActionListener aangemaakt, waarbij de bijbehorende methode actionPerformed direct wordt gedefinieerd. Deze methode roept vervolgens een methode van de klasse interface2 aan. Dit alles is slechts een kunstgreep om in dezelfde klasse als het venster de procedures te definiëren voor de afhandeling van de gebeurtenissen van de componenten van dit venster. Men zou het ook anders kunnen aanpakken:
waardoor de methode actionPerformed wordt gezocht in this, dat wil zeggen in de klasse van het venster. Deze tweede methode lijkt eenvoudiger, maar de eerste heeft een voordeel: hiermee kun je verschillende handlers gebruiken voor verschillende knoppen, terwijl dat met de tweede methode niet mogelijk is. In het laatste geval moet de enige methode actionPeformed namelijk de klikken op verschillende knoppen verwerken en dus eerst vaststellen welke knop de gebeurtenis heeft veroorzaakt, voordat ze aan de slag kan gaan.
5.2.3.2.3. De gebeurtenishandlers
We zien hier de reeds besproken handlers terug:
/**Vervangen, zodat we kunnen afsluiten wanneer het venster wordt gesloten*/
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
// Klik op de knop Weergeven
void cmdAfficher_actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(), "Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
}
5.2.3.3. Conclusion
Uit de twee onderzochte projecten kunnen we concluderen dat, zodra de grafische interface met JBuilder is gebouwd, het werk van de ontwikkelaar bestaat uit het schrijven van de gebeurtenishandlers die hij voor deze grafische interface wil beheren.
5.2.4. Hulp zoeken
Bij Java heb je vaak hulp nodig, met name vanwege het zeer grote aantal beschikbare klassen. Hier geven we enkele tips om hulp over een klasse te vinden. Kies de optie Help/Helponderwerpen in het menu.

Het helpscherm bestaat doorgaans uit twee vensters:
- het linkervenster, waar je aangeeft wat je zoekt. Dit venster heeft drie tabbladen: Sommaire, Index en Chercher.
- het venster aan de rechterkant, waarin het zoekresultaat wordt weergegeven
Er is hulp beschikbaar over het gebruik van de JBuilder-help. Kies in de JBuilder-help de optie Help/Help gebruiken. Daar wordt uitgelegd hoe u de help kunt gebruiken. Er wordt bijvoorbeeld uitgelegd wat de verschillende onderdelen van de helpviewer zijn:

Laten we de pagina’s Sommaire en Index eens wat nader bekijken.
5.2.4.1. Help: Inhoudsopgave

5.2.4.1.1. Inhoudsopgave: Inleiding tot Java
Hier vindt u de basisbeginselen van Java, maar niet alleen dat, zoals blijkt uit de lijst met onderwerpen die in deze optie aan bod komen:

5.2.4.1.2. Inhoudsopgave: Tutorials
Als we in de bovenstaande inhoudsopgave de optie Tutorials selecteren, verschijnt in het venster aan de rechterkant een lijst met beschikbare tutorials:

De basistutorials zijn bijzonder interessant om vertrouwd te raken met JBuilder. Er zijn nog veel meer tutorials dan de hierboven genoemde en wanneer u een applicatie wilt ontwikkelen, kan het nuttig zijn om eerst te controleren of er geen tutorial is die u zou kunnen helpen.
5.2.4.1.3. Overzicht: JDK
Door de optie Java 2 JDK 1.3 te selecteren, krijgt men toegang tot alle bibliotheken van JDK. Over het algemeen is dit niet de plek waar je moet zoeken als je informatie nodig hebt over een specifieke klasse en niet weet in welke bibliotheek deze zich bevindt. Deze optie is daarentegen wel interessant als je een algemeen overzicht wilt krijgen van de Java-bibliotheken.
5.2.4.2. Help: Index
Selecteer het tabblad Index in het linkervenster van de Help. Met deze optie kunt u bijvoorbeeld hulp vinden over een klasse. Stel bijvoorbeeld dat u de methoden van de invoervelden swing en JTextField wilt weten. Typ JTextField in het zoekveld:
![]()
De helpfunctie geeft de indexvermeldingen weer die beginnen met de ingevoerde tekst:

Nu hoeft u alleen nog maar te dubbelklikken op de vermelding die u interesseert, in dit geval JTextField class. De helptekst over deze klasse wordt dan in het rechtervenster weergegeven:

U krijgt dan een volledige beschrijving van de klasse te zien.
5.2.5. Enkele Swing-componenten
We presenteren nu verschillende toepassingen waarbij de meest gangbare componenten swing worden gebruikt, om de belangrijkste methoden en eigenschappen ervan te ontdekken. Voor elke toepassing laten we de grafische interface en de relevante code zien, met name die van de gebeurtenishandlers.
5.2.5.1. Componenten JLabel en JTextField
We zijn deze twee componenten al tegengekomen. JLabel is een tekstcomponent en JTextField een invoerveldcomponent. Hun twee belangrijkste methoden zijn
String getText() | om de inhoud van het invoerveld of de tekst van het label op te halen |
void setText(String unTexte) | om unTexte in het veld of het label in te voeren |
De gebeurtenissen die doorgaans voor JTextField worden gebruikt, zijn de volgende:
actionPerformed | geeft aan dat de gebruiker de ingevoerde tekst heeft bevestigd (Enter-toets) |
caretUpdate | geeft aan dat de gebruiker de invoercursor heeft verplaatst |
inputMethodChanged | geeft aan dat de gebruiker het invoerveld heeft gewijzigd |
Hier volgt een voorbeeld waarin de gebeurtenis caretUpdate wordt gebruikt om de wijzigingen in een invoerveld bij te houden:

nr. | type | naam | rol |
1 | JTextField | txtSaisie | invoerveld |
2 | JTextField | txtControle | geeft de tekst van 1 in realtime weer |
3 | JButton | cmdEffacer | om de velden 1 en 2 te wissen |
4 | JButton | cmdQuitter | om de applicatie te verlaten |
De relevante code van deze applicatie is als volgt:
import java.awt.*;
....
public class Cadre1 extends JFrame {
JPanel contentPane;
JTextField txtSaisie = new JTextField();
JLabel jLabel1 = new JLabel();
JLabel jLabel2 = new JLabel();
JTextField txtControle = new JTextField();
JButton CmdEffacer = new JButton();
JButton CmdQuitter = new JButton();
/**Het frame opbouwen*/
public Cadre1() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**De component initialiseren*/
private void jbInit() throws Exception {
....
txtSaisie.addCaretListener(new javax.swing.event.CaretListener() {
public void caretUpdate(CaretEvent e) {
txtSaisie_caretUpdate(e);
}
});
...
CmdEffacer.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
CmdEffacer_actionPerformed(e);
}
});
...
CmdQuitter.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
CmdQuitter_actionPerformed(e);
}
});
....
}
/**Vervangen, zodat we kunnen afsluiten wanneer het venster wordt gesloten*/
protected void processWindowEvent(WindowEvent e) {
...
}
void txtSaisie_caretUpdate(CaretEvent e) {
// de invoercursor is verplaatst
txtControle.setText(txtSaisie.getText());
}
void CmdQuitter_actionPerformed(ActionEvent e) {
// we verlaten de applicatie
System.exit(0);
}
void CmdEffacer_actionPerformed(ActionEvent e) {
// de inhoud van het invoerveld wordt gewist
txtSaisie.setText("");
}
}
Hier volgt een voorbeeld van de uitvoering:

5.2.5.2. component JComboBox


Een component JComboBox is een keuzelijst in combinatie met een invoerveld: de gebruiker kan ofwel een item selecteren in (2) of tekst invoeren in (1). Standaard zijn de JComboBox-componenten niet bewerkbaar. Je moet de methode setEditable(true) expliciet aanroepen om ze bewerkbaar te maken. Om de klasse JComboBox te bekijken, typ je JComboBox in de helpindex.
Het object JComboBox kan op verschillende manieren worden aangemaakt:
new JComboBox() | maakt een lege keuzelijst aan |
new JComboBox (Object[] items) | maakt een keuzelijst aan die een array met objecten bevat |
new JComboBox(Vector items) | idem met een vector van objecten |
Het is misschien verrassend dat een keuzelijst objecten kan bevatten, terwijl deze gewoonlijk tekenreeksen bevat. Visueel gezien is dit inderdaad het geval. Als een JComboBox een object obj bevat, wordt de tekenreeks obj.toString weergegeven(). We herinneren ons dat elk object een methode toString heeft, geërfd van de klasse Object, die een tekenreeks retourneert die „representatief“ is voor het object.
De nuttige methoden van de klasse JCombobox zijn de volgende:
void addItem(Object unObjet) | voegt een object toe aan de keuzelijst |
int getItemCount() | geeft het aantal items in de keuzelijst weer |
Object getItemAt(int i) | geeft het object met nummer i uit de keuzelijst terug |
void insertItemAt(Object unObjet, int i) | voegt unObjet in op positie i van de keuzelijst |
int getSelectedIndex() | geeft het nummer van het geselecteerde element in de keuzelijst |
Object getSelectedItem() | geeft het geselecteerde object in de keuzelijst terug |
void setSelectedIndex(int i) | selecteert element i uit de keuzelijst |
void setSelectedItem(Object unObjet) | selecteert het opgegeven object in de keuzelijst |
void removeAllItems() | maakt de keuzelijst leeg |
void removeItemAt(int i) | verwijdert item nr. i uit de keuzelijst |
void removeItem(Object unObjet) | verwijdert het opgegeven object uit de keuzelijst |
void setEditable(boolean val) | maakt de keuzelijst bewerkbaar (val=true) of niet (val=false) |
Bij het selecteren van een item in de keuzelijst vindt de gebeurtenis actionPerformed plaats, die vervolgens kan worden gebruikt om op de hoogte te worden gesteld van de wijziging in de selectie in de keuzelijst. In de volgende toepassing gebruiken we deze gebeurtenis om het item weer te geven dat in de lijst is geselecteerd.

We tonen alleen de relevante code van het venster.
public class Cadre1 extends JFrame {
JPanel contentPane;
JComboBox jComboBox1 = new JComboBox();
JLabel jLabel1 = new JLabel();
/**Het kader opbouwen*/
public Cadre1() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
// verwerking - de keuzelijst wordt ingevuld
String[] infos={"un","deux","trois","quatre"};
for(int i=0;i<infos.length;i++)
jComboBox1.addItem(infos[i]);
}
/**De component initialiseren*/
private void jbInit() throws Exception {
....
jComboBox1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jComboBox1_actionPerformed(e);
}
});
....
}
void jComboBox1_actionPerformed(ActionEvent e) {
// er is een nieuw element geselecteerd – dit wordt weergegeven
JOptionPane.showMessageDialog(this,jComboBox1.getSelectedItem(),
"actionPerformed",JOptionPane.INFORMATION_MESSAGE);
}
}
5.2.5.3. component JList
De Swing-component JList is complexer dan zijn tegenhanger uit de bibliotheek, awt. Er zijn twee belangrijke verschillen:
- de inhoud van de lijst wordt beheerd door een ander object dan de lijst zelf. Hier gebruiken we een DefaultListModel-object, dat op dezelfde manier wordt gebruikt als een Vector, maar dat bovendien het JList-object waarschuwt zodra de inhoud verandert, zodat de visuele weergave van de lijst ook wordt aangepast.
- De lijst is standaard niet scrollbaar. De lijst moet in een container ScrollPane worden geplaatst, die scrollen mogelijk maakt.
In de broncode kan een lijst als volgt worden gedefinieerd:
// de vector met de waarden van de lijst
DefaultlistModel valeurs=new DefaultListModel();
// de lijst zelf waaraan de vector met de waarden wordt gekoppeld
JList jList1 = new JList(valeurs);
// de scrollbare container waarin de lijst wordt geplaatst om een scrollbare lijst te krijgen
JScrollPane jScrollPane1 = new JScrollPane(jList1);
Om de lijst jList1 op te nemen in de container jScrollPane1, gaat de door JBuilder gegenereerde code anders te werk:
- de container wordt opgegeven in de vensterattributen
- en vervolgens wordt de lijst in de code van jbInit aan de container gekoppeld
Om waarden toe te voegen aan de bovenstaande lijst JList1, volstaat het deze toe te voegen aan de bijbehorende waardenvector valeurs:
en dan krijg je het volgende venster:

Hoe is deze interface opgebouwd?
- We kiezen een component JScrollPane op de pagina „Swing-containers“ van de componenten en plaatsen deze in het venster, waarbij we de afmetingen aanpassen naar de gewenste grootte
- We kiezen een component JList op de pagina "Swing" van de componenten en plaatsen deze in de container JScrollPane, waar hij vervolgens de volledige ruimte inneemt.
De door JBuilder gegenereerde code moet enigszins worden aangepast om de volgende code te verkrijgen:
public class interfaceAppli extends JFrame {
JPanel contentPane;
JLabel jLabel1 = new JLabel();
DefaultListModel valeurs=new DefaultListModel();
JList jList1 = new JList(valeurs);
JScrollPane jScrollPane1 = new JScrollPane();
JLabel jLabel2 = new JLabel();
/**Het frame opbouwen*/
public interfaceAppli() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
// verwerking
// de lijst wordt opgenomen in de scrollPane
// lijst initialiseren
for(int i=0;i<10;i++)
valeurs.addElement(""+i);
}
/**De component initialiseren*/
private void jbInit() throws Exception {
....
// de lijst jList1 is gekoppeld aan de container jcrollPane1
jScrollPane1.getViewport().add(jList1, null);
}
/**Vervangen, zodat we kunnen afsluiten wanneer het venster wordt gesloten*/
protected void processWindowEvent(WindowEvent e) {
....
}
}
Laten we nu de belangrijkste methoden van de klasse JList bekijken door JList op te zoeken in de index van de help. Het object JList kan op verschillende manieren worden aangemaakt:

Een eenvoudige methode is degene die we hebben gebruikt: maak een leeg DefaultListModel V aan en koppel dit vervolgens aan de te maken lijst met new JList(V). De inhoud van de lijst wordt niet beheerd door het object JList, maar door het object dat de waarden van de lijst bevat. Als de inhoud is opgebouwd met behulp van een DefaultListModel-object dat is gebaseerd op de klasse Vector, kunnen de methoden van de klasse Vector worden gebruikt om elementen aan de lijst toe te voegen, in te voegen en te verwijderen. Een lijst kan een enkele of meervoudige selectie zijn. Dit wordt bepaald door de methode setSelectionMode:

Met getSelectionMode kan de huidige selectiemodus worden vastgesteld:
![]()
Het geselecteerde element of de geselecteerde elementen kunnen via de volgende methoden worden opgehaald:

We kunnen een vector met waarden koppelen aan een lijst met de constructor JList(DefaultListModel). Omgekeerd kunnen we het object DefaultListModel uit een lijst JList ophalen via:

We weten nu genoeg om de volgende toepassing te schrijven:

De onderdelen van dit venster zijn als volgt:
nr. | type | naam | functie |
1 | JTextField | txtSaisie | invoerveld |
2 | JList | jList1 | lijst in een container jScrollPane1 |
3 | JList | jList2 | lijst in een container jScrollPane2 |
4 | JButton | cmd1To2 | verplaatst de geselecteerde items van lijst 1 naar lijst 2 |
5 | JButton | cmd2To1 | doet het omgekeerde |
6 | JButton | cmdRaz1 | maak lijst 1 leeg |
7 | JButton | cmdRaz2 | lijst 2 leegmaken |
De gebruiker typt tekst in veld (1) en bevestigt deze. Vervolgens vindt de gebeurtenis actionPerformed plaats op het invoerveld, waarmee de ingevoerde tekst aan lijst 1 wordt toegevoegd. Hieronder staat de code voor deze eerste functie:
public class interfaceAppli extends JFrame {
JPanel contentPane;
JLabel jLabel1 = new JLabel();
JLabel jLabel2 = new JLabel();
JLabel jLabel3 = new JLabel();
JTextField txtSaisie = new JTextField();
JButton cmd1To2 = new JButton();
JButton cmd2To1 = new JButton();
DefaultListModel v1=new DefaultListModel();
DefaultListModel v2=new DefaultListModel();
JList jList1 = new JList(v1);
JList jList2 = new JList(v2);
JScrollPane jScrollPane1 = new JScrollPane();
JScrollPane jScrollPane2 = new JScrollPane();
JButton cmdRaz1 = new JButton();
JButton cmdRaz2 = new JButton();
JLabel jLabel4 = new JLabel();
/**Het frame opbouwen*/
public interfaceAppli() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}//interfaceAppli
/**De component initialiseren*/
private void jbInit() throws Exception {
...
txtSaisie.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
txtSaisie_actionPerformed(e);
}
});
...
// Jlist1 wordt in de container geplaatst jScrollPane1
jScrollPane1.getViewport().add(jList1, null);
// Jlist2 wordt in de container geplaatst jScrollPane2
jScrollPane2.getViewport().add(jList2, null);
...
}
/**Vervangen, zodat we kunnen afsluiten wanneer het venster wordt gesloten*/
protected void processWindowEvent(WindowEvent e) {
...
}
void txtSaisie_actionPerformed(ActionEvent e) {
// de ingevoerde tekst is gevalideerd
// we halen het op zonder de spaties aan het begin en einde
String texte=txtSaisie.getText().trim();
// als het leeg is, hebben we het niet nodig
if(texte.equals("")){
// foutmelding
JOptionPane.showMessageDialog(this,"Vous devez taper un texte",
"Erreur",JOptionPane.WARNING_MESSAGE);
// einde
return;
}//if
// als het niet leeg is, voegen we het toe aan de waarden in lijst 1
v1.addElement(texte);
// en wordt het invoerveld leeggemaakt
txtSaisie.setText("");
}/// txtSaisie_actionperformed
}//klasse
De code voor het overzetten van de geselecteerde items van de ene lijst naar de andere is als volgt:
void cmd1To2_actionPerformed(ActionEvent e) {
// de geselecteerde items uit lijst 1 overbrengen naar lijst 2
transfert(jList1,jList2);
}//cmd1To2
void cmd2To1_actionPerformed(ActionEvent e) {
// overdracht van de geselecteerde elementen in jList2 naar jList1
transfert(jList2,jList1);
}//cmd2TO1
private void transfert(JList L1, JList L2){
// overdracht van de geselecteerde elementen uit lijst 1 naar lijst 2
// de indexen van de geselecteerde elementen worden opgehaald in L1
int[] indices=L1.getSelectedIndices();
// moet er iets gebeuren?
if (indices.length==0) return;
// de waarden uit L1 worden opgehaald
DefaultListModel v1=(DefaultListModel)L1.getModel();
// en die uit L2
DefaultListModel v2=(DefaultListModel)L2.getModel();
for(int i=indices.length-1;i>=0;i--){
// de in L1 geselecteerde waarden worden toegevoegd aan L2
v2.addElement(v1.elementAt(indices[i]));
// de elementen van L1 die naar L2 zijn gekopieerd, moeten uit L1 worden verwijderd
v1.removeElementAt(indices[i]);
}//voor
}//overdracht
De code die bij de knoppen Raz hoort, is heel eenvoudig:
void cmdRaz1_actionPerformed(ActionEvent e) {
// lijst 1 leegmaken
v1.removeAllElements();
}//cmd Raz1
void cmdRaz2_actionPerformed(ActionEvent e) {
// lijst 2 leegmaken
v2.removeAllElements();
}///cmd Raz2
5.2.5.4. Selectievakjes JCheckBox, keuzerondjes JButtonRadio
We willen de volgende applicatie schrijven:

De componenten van het venster zijn als volgt:
nr. | type | naam | functie |
1 | JButtonRadio | jButtonRadio1 jButtonRadio2 jButtonRadio3 | 3 keuzerondjes die deel uitmaken van de groep buttonGroup1 |
2 | JCheckBox | jCheckBox1 jCheckBox2 jCheckBox3 | 3 selectievakjes |
3 | JList | jList1 | een lijst in een container jScrollPane1 |
4 | ButtonGroup | buttonGroup1 | onzichtbaar onderdeel – dient om de 3 keuzerondjes te groeperen, zodat wanneer er één oplicht, de andere uitgaan. |
Een groep keuzerondjes kan als volgt worden opgebouwd:
- plaats elk van de keuzerondjes zonder ze te groeperen
- plaats in de container een Swing-component ButtonGroup. Deze component is niet-visueel. Hij verschijnt dus niet in de vensterontwerper. Hij verschijnt echter wel in de structuur:

Hierboven zien we in de tak Autre de niet-visuele attributen van het venster. Zodra een groep keuzerondjes is aangemaakt, kunnen we elk keuzerondje aan deze groep toewijzen. Hiervoor selecteren we de eigenschappen van het keuzerondje:

en in de eigenschap buttonGroup van de keuzeknop voert u de naam in van de groep waarin u de keuzeknop wilt plaatsen, in dit geval buttonGroup1. Herhaal deze handeling voor de 3 keuzeknoppen.
De belangrijkste methode voor keuzerondjes en selectievakjes is de methode isSelected(), die aangeeft of het selectievakje of het keuzerondje is aangevinkt. De tekst die aan het onderdeel is gekoppeld, kan worden opgehaald met getText() en ingesteld met setText(String unTexte). Het selectievakje of de keuzeknop kan worden aangevinkt met de methode setSelected(boolean value).
Bij het klikken op een keuzerondje of selectievakje wordt de gebeurtenis actionPerformed geactiveerd. In de volgende code gebruiken we deze gebeurtenis om de waardeveranderingen van de keuzerondjes en selectievakjes bij te houden:
public class interfaceAppli extends JFrame {
JPanel contentPane;
JRadioButton jRadioButton1 = new JRadioButton();
JRadioButton jRadioButton2 = new JRadioButton();
JRadioButton jRadioButton3 = new JRadioButton();
JCheckBox jCheckBox1 = new JCheckBox();
JCheckBox jCheckBox2 = new JCheckBox();
JCheckBox jCheckBox3 = new JCheckBox();
ButtonGroup buttonGroup1 = new ButtonGroup();
JScrollPane jScrollPane1 = new JScrollPane();
DefaultListModel valeurs=new DefaultListModel();
JList jList1 = new JList(valeurs);
/**Frame opbouwen*/
public interfaceAppli() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**De component initialiseren*/
private void jbInit() throws Exception {
jRadioButton1.setSelected(true);
jRadioButton1.setText("un");
jRadioButton1.setBounds(new Rectangle(57, 31, 49, 23));
jRadioButton1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
afficheRadioButtons(e);
}
});
jRadioButton2.setBounds(new Rectangle(113, 30, 49, 23));
jRadioButton2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
afficheRadioButtons(e);
}
});
jRadioButton2.setText("deux");
jRadioButton3.setBounds(new Rectangle(168, 30, 49, 23));
jRadioButton3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
afficheRadioButtons(e);
}
});
jRadioButton3.setText("trois");
// de keuzerondjes zijn gegroepeerd
buttonGroup1.add(jRadioButton1);
buttonGroup1.add(jRadioButton2);
buttonGroup1.add(jRadioButton3);
// selectievakjes
jCheckBox1.setText("A");
jCheckBox1.setBounds(new Rectangle(58, 69, 32, 17));
jCheckBox1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
afficheCases(e);
}
});
jCheckBox2.setBounds(new Rectangle(112, 69, 40, 17));
jCheckBox2.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
afficheCases(e);
}
});
jCheckBox2.setText("B");
jCheckBox3.setText("C");
jCheckBox3.setBounds(new Rectangle(170, 69, 37, 17));
jCheckBox3.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
afficheCases(e);
}
});
....
}
/**Vervangen, zodat we kunnen afsluiten wanneer het venster wordt gesloten*/
protected void processWindowEvent(WindowEvent e) {
...
}
private void afficheRadioButtons(ActionEvent e){
// geeft de waarden van de 3 keuzerondjes weer
valeurs.addElement("boutons radio=("+jRadioButton1.isSelected()+","+
jRadioButton2.isSelected()+","+jRadioButton3.isSelected()+")");
}//afficheRadioButtons
void afficheCases(ActionEvent e) {
// geeft de waarden van de selectievakjes weer
valeurs.addElement("cases à cocher=["+jCheckBox1.isSelected()+","+
jCheckBox2.isSelected()+","+jCheckBox3.isSelected()+")");
}//afficheCases
}//sorteert
Hier volgt een voorbeeld van de uitvoering:

5.2.5.5. component JScrollBar
Laten we de volgende toepassing maken:

nr. | type | naam | rol |
1 | JScrollBar | jScrollBar1 | een horizontale variator |
2 | JScrollBar | jScrollBar2 | een verticale variator |
3 | JTextField | txtvaleurHS | geeft de waarde van de horizontale variator weer 1 - hiermee kan deze waarde ook worden vastgezet |
4 | JTextField | txtvaleurVS | geeft de waarde van de verticale regelaar 2 weer – hiermee kan deze waarde ook worden vastgezet |
- Met een schuifregelaar JScrollBar kan de gebruiker een waarde kiezen binnen een bereik van gehele getallen, gesymboliseerd door de "strook" van de schuifregelaar waarover een cursor beweegt.
- Bij een horizontale schuifregelaar vertegenwoordigt het linkeruiteinde de minimumwaarde van het bereik, het rechteruiteinde de maximumwaarde en de schuifknop de huidige gekozen waarde. Bij een verticale schuifregelaar wordt het minimum weergegeven door het bovenste uiteinde en het maximum door het onderste uiteinde. Het koppel (min,max) is standaard ingesteld op (0,100).
- Een klik op de uiteinden van de schuifregelaar verandert de waarde met één stap (positief of negatief), afhankelijk van het aangeklikte uiteinde, genaamd unitIncrement, dat standaard 1 is.
- Een klik aan weerszijden van de schuifbalk verandert de waarde met één stap (positief of negatief), afhankelijk van het aangeklikte uiteinde, genaamd blockIncrement, dat standaard 10 is.
- Deze vijf waarden (min, max, waarde, unitIncrement, blockIncrement) kunnen worden bepaald met de methoden getMinimum(), getMaximum(), getValue(), getUnitIncrement() en getBlockIncrement(), die allemaal een geheel getal retourneren en kunnen worden ingesteld met de methoden setMinimum(int min), setMaximum(int max), setValue(int val), setUnitIncrement(int uInc), setBlockIncrement(int bInc)
Er zijn een aantal zaken die u moet weten bij het gebruik van de componenten JScrollBar. Allereerst vindt u deze in de Swing-componentenbalk:

Wanneer je deze op de container plaatst, staat hij standaard verticaal. Je kunt hem horizontaal maken met de onderstaande eigenschap orientation:

Op het bovenstaande eigenschappenvenster zien we dat we toegang hebben tot de eigenschappen minimum, maximum, value, unitIncrement, blockIncrement van de JScrollbar. Deze kunnen dus tijdens het ontwerpen worden ingesteld. Wanneer er een schuifbalk op de container wordt geplaatst, verschijnt de "variatiebalk" niet:

Dit probleem kan worden opgelost door de component een rand te geven. Dit gebeurt met de eigenschap border, die verschillende waarden kan aannemen:

Dit is bijvoorbeeld het resultaat van RaisedBevel:
![]()
Wanneer men op het bovenste uiteinde van een verticale schuifregelaar klikt, neemt de waarde ervan af. Dit kan de gemiddelde gebruiker verrassen, die normaal gesproken verwacht dat de waarde “stijgt”. Dit probleem lost men op door een negatieve waarde toe te kennen aan unitIncrement en blockIncrement.
Hoe kun je de veranderingen van een schuifbalk volgen? Wanneer de waarde ervan verandert, vindt de gebeurtenis adjustmentValueChanged plaats. Je hoeft alleen maar een procedure aan deze gebeurtenis te koppelen om op de hoogte te worden gehouden van elke verandering in de waarde van de schuifbalk.

De relevante code van onze applicatie is als volgt:
....
public class cadreAppli extends JFrame {
JPanel contentPane;
JScrollBar jScrollBar1 = new JScrollBar();
Border border1;
JTextField txtValeurHS = new JTextField();
JScrollBar jScrollBar2 = new JScrollBar();
JTextField txtValeurVS = new JTextField();
TitledBorder titledBorder1;
/**Het kader opbouwen*/
public cadreAppli() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**De component initialiseren*/
private void jbInit() throws Exception {
...
// een rand voor de schuifbalken
border1 = BorderFactory.createBevelBorder(BevelBorder.RAISED,Color.white,Color.white,new Color(134, 134, 134),new Color(93, 93, 93));
// geen titelbalk
titledBorder1 = new TitledBorder("");
jScrollBar1.setOrientation(JScrollBar.HORIZONTAL);
jScrollBar1.setBorder(BorderFactory.createRaisedBevelBorder());
jScrollBar1.setAutoscrolls(true);
jScrollBar1.setBounds(new Rectangle(37, 17, 218, 20));
jScrollBar1.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent e) {
jScrollBar1_adjustmentValueChanged(e);
}
});
txtValeurHS.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
txtValeurHS_actionPerformed(e);
}
});
jScrollBar2.setBounds(new Rectangle(39, 51, 30, 27));
jScrollBar2.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
public void adjustmentValueChanged(AdjustmentEvent e) {
jScrollBar2_adjustmentValueChanged(e);
}
});
jScrollBar2.setAutoscrolls(true);
jScrollBar2.setUnitIncrement(-1);
jScrollBar2.setBorder(BorderFactory.createRaisedBevelBorder());
txtValeurVS.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
txtValeurVS_actionPerformed(e);
}
});
......
}
/**Vervangen, zodat we kunnen afsluiten wanneer het venster wordt gesloten*/
protected void processWindowEvent(WindowEvent e) {
...
}
void jScrollBar1_adjustmentValueChanged(AdjustmentEvent e) {
// de waarde van schuifbalk 1 is gewijzigd
txtValeurHS.setText(""+jScrollBar1.getValue());
}
void jScrollBar2_adjustmentValueChanged(AdjustmentEvent e) {
// de waarde van schuifbalk 2 is gewijzigd
txtValeurVS.setText(""+jScrollBar2.getValue());
}
void txtValeurHS_actionPerformed(ActionEvent e) {
// de waarde van de horizontale schuifbalk wordt vastgezet
setValeur(jScrollBar1,txtValeurHS);
}
void txtValeurVS_actionPerformed(ActionEvent e) {
// de waarde van de verticale schuifbalk wordt vastgezet
setValeur(jScrollBar2,txtValeurVS);
}
private void setValeur(JScrollBar jS, JTextField jT){
// de waarde van de schuifbalk jS wordt vastgelegd met de tekst uit het veld jT
int valeur=0;
try{
valeur=Integer.parseInt(jT.getText());
jS.setValue(valeur);
}
catch (Exception e){
// de fout wordt weergegeven
afficher(""+e);
}//try-catch
}//setValeur
void afficher(String message){
// geeft een bericht weer in een venster
JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
}//weergeven
}
Hier volgt een voorbeeld van de uitvoering:

5.2.5.6. component JTextArea
De component JTextArea is een component waarin meerdere regels tekst kunnen worden ingevoerd, in tegenstelling tot de component JTextField, waarin slechts één regel kan worden ingevoerd. Als deze component in een scrollbare container (JScrollPane) wordt geplaatst, ontstaat er een scrollbaar tekstinvoerveld. Dit type component kan bijvoorbeeld voorkomen in een e-mailtoepassing, waarbij de tekst van het te verzenden bericht wordt getypt in een component JTextArea. De gebruikelijke methoden zijn String getText() om de inhoud van het tekstveld op te vragen, setText(String unTexte) om unTexte in het tekstveld te plaatsen, en append(String unTexte) om unTexte toe te voegen aan de tekst die al in het tekstveld staat. Laten we eens kijken naar de volgende toepassing:

nr. | type | naam | rol |
1 | JTextArea | txtTexte | een tekstvak met meerdere regels |
2 | JButton | cmdAfficher | geeft de inhoud van 1 weer in een dialoogvenster |
3 | JButton | cmdEffacer | wist de inhoud van 1 |
4 | JTextField | txtAjout | tekst die aan de tekst van 1 wordt toegevoegd wanneer deze met de Enter-toets wordt bevestigd. |
5 | JScrollPane | jScrollPane1 | scrollbare container waarin tekstvak 1 is geplaatst om een scrollbaar tekstvak te verkrijgen. |
De benodigde code is als volgt:
.....
public class cadreAppli extends JFrame {
JPanel contentPane;
JLabel jLabel1 = new JLabel();
JButton cmdAfficher = new JButton();
JScrollPane jScrollPane1 = new JScrollPane();
JTextArea txtTexte = new JTextArea();
JLabel jLabel2 = new JLabel();
JTextField txtAjout = new JTextField();
JButton cmdEffacer = new JButton();
/**Het frame opbouwen*/
public cadreAppli() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**De component initialiseren*/
private void jbInit() throws Exception {
cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
cmdAfficher_actionPerformed(e);
}
});
txtAjout.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
txtAjout_actionPerformed(e);
}
});
cmdEffacer.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
cmdEffacer_actionPerformed(e);
}
});
.......
jScrollPane1.getViewport().add(txtTexte, null);
}
/**Vervangen, zodat we kunnen afsluiten wanneer het venster wordt gesloten*/
protected void processWindowEvent(WindowEvent e) {
........
}
void cmdAfficher_actionPerformed(ActionEvent e) {
// geeft de inhoud van TextArea weer
afficher(txtTexte.getText());
}
void afficher(String message){
// geeft een bericht weer in een venster
JOptionPane.showMessageDialog(this,message,"Suivi",JOptionPane.INFORMATION_MESSAGE);
}// weergeven
void cmdEffacer_actionPerformed(ActionEvent e) {
txtTexte.setText("");
}//cmdEffacer_actionPerformed
void txtAjout_actionPerformed(ActionEvent e) {
// tekst toevoegen
txtTexte.append(txtAjout.getText());
// tekst wissen
txtAjout.setText("");
}//
}
5.2.6. Muisgebeurtenissen
Wanneer je in een container tekent, is het belangrijk om de positie van de muis te kennen, bijvoorbeeld om bij een klik een punt weer te geven. De bewegingen van de muis veroorzaken gebeurtenissen in de container waarin de muis zich verplaatst. Hieronder staan bijvoorbeeld de gebeurtenissen die door JBuilder worden aangeboden voor een container JPanel:

mouseClicked | muisklik |
mouseDragged | de muis beweegt, linkermuisknop ingedrukt |
mouseEntered | de muis is zojuist het gebied van de container binnengekomen |
mouseExited | de muis heeft zojuist het gebied van de container verlaten |
mouseMoved | de muis beweegt |
mousePressed | De linkermuisknop is ingedrukt |
mouseReleased | De linkermuisknop wordt losgelaten |
Hier is een programma waarmee je beter kunt begrijpen wanneer de verschillende muisgebeurtenissen plaatsvinden:

nr. | type | naam | rol |
1 | JTextField | txtPosition | om de positie van de muis in de container weer te geven (evt. MouseMoved) |
2 | JList | lstAffichage | om andere muisgebeurtenissen dan MouseMoved weer te geven |
3 | JButton | cmdEffacer | om de inhoud van 2 te wissen |
Wanneer je dit programma uitvoert, krijg je bij een muisklik het volgende te zien:

De gebeurtenissen worden van bovenaf in de lijst gestapeld. Uit de bovenstaande schermafbeelding blijkt dus dat één klik drie gebeurtenissen veroorzaakt, in de volgende volgorde:
- MousePressed wanneer de knop wordt ingedrukt
- MouseReleased wanneer de knop wordt losgelaten
- MouseClicked, wat aangeeft dat de opeenvolging van de twee voorgaande gebeurtenissen als een klik wordt beschouwd. Dit zou een dubbelklik kunnen zijn. Maar hierboven geeft de informatie clickCount=1 aan dat het om een enkele klik gaat.
Als je nu de knop indrukt, de muis verplaatst en de knop loslaat:

We zien hier de drie gebeurtenissen:
- MousePressed wanneer de knop voor het eerst wordt ingedrukt
- MouseDragged wanneer de muis wordt bewogen terwijl de knop ingedrukt is
- MouseReleased wanneer de knop wordt losgelaten
In de twee bovenstaande voorbeelden zien we dat een muisgebeurtenis diverse gegevens met zich meebrengt, waaronder de (x,y)-coördinaten van de muis, bijvoorbeeld (408,65) in de eerste regel hierboven.
Als we zo verdergaan, ontdekken we dat de gebeurtenis MouseExited wordt geactiveerd zodra de muis de container verlaat of over een van de componenten ervan beweegt. In dat laatste geval ontvangt de container de gebeurtenis MouseExited en het onderdeel de gebeurtenis MouseEntered. Het omgekeerde gebeurt wanneer de muis het onderdeel verlaat om terug te keren naar de container.
Wat gebeurt er bij een dubbelklik?

We hebben precies dezelfde gebeurtenissen als bij een enkele klik. Alleen bevat de gebeurtenis de informatie clickCount=2 (zie hierboven), wat aangeeft dat er in feite een dubbele klik heeft plaatsgevonden.
De relevante code van deze toepassing is als volgt:
public class Cadre1 extends JFrame {
JPanel contentPane;
JLabel jLabel1 = new JLabel();
JTextField txtPosition = new JTextField();
JScrollPane jScrollPane1 = new JScrollPane();
DefaultListModel valeurs=new DefaultListModel();
JList lstAffichage = new JList(valeurs);
JButton cmdEffacer = new JButton();
/**Het kader opbouwen*/
public Cadre1() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**De component initialiseren*/
private void jbInit() throws Exception {
contentPane.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
public void mouseMoved(MouseEvent e) {
contentPane_mouseMoved(e);
}
public void mouseDragged(MouseEvent e) {
contentPane_mouseDragged(e);
}
});
contentPane.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseEntered(MouseEvent e) {
contentPane_mouseEntered(e);
}
public void mouseExited(MouseEvent e) {
contentPane_mouseExited(e);
}
public void mousePressed(MouseEvent e) {
contentPane_mousePressed(e);
}
public void mouseClicked(MouseEvent e) {
contentPane_mouseClicked(e);
}
public void mouseReleased(MouseEvent e) {
contentPane_mouseReleased(e);
}
});
cmdEffacer.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
cmdEffacer_actionPerformed(e);
}
});
jScrollPane1.getViewport().add(lstAffichage, null);
...............
}
/**Vervangen, zodat we kunnen afsluiten wanneer het venster wordt gesloten*/
protected void processWindowEvent(WindowEvent e) {
.........
}
void contentPane_mouseMoved(MouseEvent e) {
txtPosition.setText("("+e.getX()+","+e.getY()+")");
}
void contentPane_mouseDragged(MouseEvent e) {
afficher(e);
}
void contentPane_mouseEntered(MouseEvent e) {
afficher(e);
}
void afficher(MouseEvent e){
// gebeurtenis e weergeven in de lijst lstAffichage
valeurs.insertElementAt(e,0);
}
void contentPane_mouseExited(MouseEvent e) {
afficher(e);
}
void contentPane_mousePressed(MouseEvent e) {
afficher(e);
}
void contentPane_mouseClicked(MouseEvent e) {
afficher(e);
}
void contentPane_mouseReleased(MouseEvent e) {
afficher(e);
}
void cmdEffacer_actionPerformed(ActionEvent e) {
// wist de lijst
valeurs.removeAllElements();
}
}
5.2.7. Een venster met menu maken
Laten we nu eens kijken hoe we met JBuilder een venster met een menu kunnen maken. We gaan het volgende venster maken:


Maak een nieuw project aan met in eerste instantie een leeg venster. Kies in de lijst met componenten “Swing-containers” de component JMenuBar (zie afbeelding 1 hieronder) en plaats deze in het venster dat u aan het ontwerpen bent.

Er verschijnt niets in het ontwerpvenster, maar de component JMenuBar verschijnt in het structuurpaneel van uw venster:

Dubbelklik op het bovenstaande element jMenuBar1 om toegang te krijgen tot het menu in de ontwerpmodus:

1 | een menu-item invoegen |
2 | een scheidingsteken invoegen |
3 | een genest menu invoegen |
4 | een menu-item verwijderen |
5 | een menu-item uitschakelen |
6 | menu-item aanvinken |
7 | de keuzeknop omdraaien |
Om uw eerste menu-item aan te maken, typt u "Opties A" in het vakje A hierboven, en vervolgens daaronder in deze volgorde: A1, A2, scheidingsteken, A3, A4.

Daarnaast:

Gebruik tool 3 om aan te geven dat B3 een genest submenu is.
Naarmate het ontwerp van het menu vordert, verandert de logische structuur van ons venster:

Als we onze applicatie nu uitvoeren, zien we een leeg venster zonder menu. We moeten het aangemaakte menu aan ons venster koppelen. Selecteer hiervoor in de vensterstructuur het object this:

U krijgt dan toegang tot de eigenschappen van this:

Een van deze eigenschappen is JMenuBar, waarmee u het menu kunt vastleggen dat aan het venster wordt gekoppeld. Klik in de cel rechts van JMenuBar. U krijgt dan een lijst met alle aangemaakte menu’s te zien. In dit geval hebben we alleen jMenuBar1. Selecteer deze.
Start de toepassing (F9):

Nu hebben we een menu, maar de opties doen voorlopig nog niets. De menuopties worden behandeld als componenten: ze hebben eigenschappen en gebeurtenissen. Selecteer in de menustructuur de optie jMenuItem1:

Je hebt dan toegang tot de eigenschappen en gebeurtenissen ervan:

Selecteer de gebeurtenispagina en klik op de cel rechts van de gebeurtenis actionPerformed: dit is de gebeurtenis die plaatsvindt wanneer er op een menu-item wordt geklikt. Er wordt standaard een verwerkingsprocedure voorgesteld. Dubbelklik erop om toegang te krijgen tot de code:

We schrijven de volgende eenvoudige code:
void jMenuItem1_actionPerformed(ActionEvent e) {
afficher("L'option A1 a été sélectionnée");
}
void afficher(String message){
// geeft een bericht weer in een venster
JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
}//weergeven
Start de applicatie en selecteer de optie A1 om het volgende bericht te krijgen:

De relevante code van deze applicatie is als volgt:
.....
public class Cadre1 extends JFrame {
JPanel contentPane;
BorderLayout borderLayout1 = new BorderLayout();
JMenuBar jMenuBar1 = new JMenuBar();
JMenu jMenu1 = new JMenu();
JMenuItem jMenuItem1 = new JMenuItem();
JMenuItem jMenuItem2 = new JMenuItem();
JMenuItem jMenuItem3 = new JMenuItem();
JMenuItem jMenuItem4 = new JMenuItem();
JMenu jMenu2 = new JMenu();
JMenuItem jMenuItem5 = new JMenuItem();
JMenuItem jMenuItem6 = new JMenuItem();
JMenu jMenu3 = new JMenu();
JMenuItem jMenuItem7 = new JMenuItem();
JMenuItem jMenuItem8 = new JMenuItem();
JMenuItem jMenuItem9 = new JMenuItem();
/**Het frame opbouwen*/
public Cadre1() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**De component initialiseren*/
private void jbInit() throws Exception {
// het venster is gekoppeld aan een menu
this.setJMenuBar(jMenuBar1);
jMenu1.setText("Options A");
jMenuItem1.setText("A1");
jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
jMenuItem1_actionPerformed(e);
}
});
jMenuItem2.setText("A2");
jMenuItem3.setText("A3");
jMenuItem4.setText("A4");
jMenu2.setText("Options B");
jMenuItem5.setText("B1");
jMenuItem6.setText("B2");
jMenu3.setText("B3");
jMenuItem7.setText("B31");
jMenuItem8.setText("B32");
jMenuItem9.setText("B4");
jMenuBar1.add(jMenu1);
jMenuBar1.add(jMenu2);
jMenu1.add(jMenuItem1);
jMenu1.add(jMenuItem2);
jMenu1.addSeparator();
jMenu1.add(jMenuItem3);
jMenu1.add(jMenuItem4);
jMenu2.add(jMenuItem5);
jMenu2.add(jMenuItem6);
jMenu2.add(jMenu3);
jMenu2.add(jMenuItem9);
jMenu3.add(jMenuItem7);
jMenu3.add(jMenuItem8);
}
/**Vervangen, zodat we kunnen afsluiten wanneer het venster wordt gesloten*/
protected void processWindowEvent(WindowEvent e) {
....
}
void jMenuItem1_actionPerformed(ActionEvent e) {
afficher("L'option A1 a été sélectionnée");
}
void afficher(String message){
// geeft een bericht weer in een venster
JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
}//weergeven
}
5.3. Dialoogvensters
5.3.1. Meldingsvensters
We hebben de klasse JOptionPane al gebruikt om berichten weer te geven. Zoals in de volgende code:
import javax.swing.*;
public class dialog1 {
public static void main(String arg[]){
JOptionPane.showMessageDialog(null,"Un message","Titre de la boîte",JOptionPane.INFORMATION_MESSAGE);
}
}
geeft de volgende box weer:

Wanneer dit venster wordt gesloten, verdwijnt het, maar de uitvoeringsthread waarin het werd uitgevoerd, wordt niet gestopt. Dit verschijnsel doet zich normaal gesproken niet voor. De dialoogvensters worden gebruikt binnen een toepassing die op een bepaald moment de instructie System.exit(n) gebruikt om alle threads te stoppen. We zullen hier in de volgende voorbeelden, die allemaal volgens hetzelfde patroon zijn opgebouwd, op terugkomen. Onder DOS kan de toepassing worden onderbroken met Ctrl-C. Met JBuilder gebruiken we de optie Programma uitvoeren/herstellen (Ctrl-F2). Overigens is het eerste argument van showMessageDialog hier null. Meestal is dit niet het geval. Meestal is het this, waarbij this het hoofdvenster van de toepassing aanduidt.
5.3.2. Uiterlijk en bediening
Het uiterlijk van het bovenstaande venster kan afwijken. Dit uiterlijk kan worden ingesteld via de klasse javax.swing.UIManager. Toen we de door JBuilder gegenereerde code voor ons eerste venster doorliepen, kwamen we een instructie tegen waar we niet verder op zijn ingegaan:
Met de methode setLookAndFeel van de klasse UIManager (UI = User Interface) kan de weergave van de grafische interfaces worden bepaald. De klasse UIManager beschikt over een methode waarmee de mogelijke „uiterlijke kenmerken“ van de interfaces kunnen worden achterhaald:
static UIManager.LookAndFeelInfo[] | getInstalledLookAndFeels() |
De methode retourneert een array met elementen van het type LookAndFeelInfo. Deze klasse heeft een methode:
String | getClassName() |
die de naam opgeeft van de klasse die een bepaald uiterlijk „implementeert”. Laten we het volgende programma eens uitproberen:
import javax.swing.*;
public class LookAndFeels {
// toont de beschikbare look-and-feels
public static void main(String[] args) {
// lijst de geïnstalleerde look-and-feels weer
UIManager.LookAndFeelInfo[] lf=UIManager.getInstalledLookAndFeels();
// weergave
for(int i=0;i<lf.length;i++){
System.out.println(lf[i].getClassName());
}//voor
}//hoofdpagina
}//sorteren
Dit levert de volgende resultaten op:
javax.swing.plaf.metal.MetalLookAndFeel
com.sun.java.swing.plaf.motif.MotifLookAndFeel
com.sun.java.swing.plaf.windows.WindowsLookAndFeel
Er lijken dus drie verschillende "weergaven" te zijn. Laten we ons programma voor het weergeven van berichten nog eens bekijken en de verschillende mogelijke weergaven uitproberen:
import javax.swing.*;
public class LookAndFeel2 {
// toont de beschikbare look-and-feels
public static void main(String[] args) {
// lijst met geïnstalleerde look-and-feels
UIManager.LookAndFeelInfo[] lf=UIManager.getInstalledLookAndFeels();
// weergave
for(int i=0;i<lf.length;i++){
// uiterlijkbeheerder
try{
UIManager.setLookAndFeel(lf[i].getClassName());
}catch(Exception ex){
System.err.println(ex.getMessage());
}//catch
// bericht
JOptionPane.showMessageDialog(null,"Un message",lf[i].getClassName(),JOptionPane.INFORMATION_MESSAGE);
}//for
}//main
}//klasse
De uitvoering levert de volgende weergaven op:
![]() | ![]() | ![]() |
die van rechts naar links overeenkomen met de "looks" Metal, Motif en Windows.
5.3.3. Bevestigingsvensters
De klasse JOptionPane heeft een methode showConfirmDialog om bevestigingsvensters weer te geven met de knoppen Oui, Non, Annuler. Er zijn verschillende overladen methoden showConfirmDialog. We bekijken er één:
static int | showConfirmDialog(Component parentComponent, Object message, String title, int optionType) |
parentComponent | de bovenliggende component van het dialoogvenster. Vaak is dit het venster of de waarde null |
message | het weer te geven bericht |
title | de titel van het dialoogvenster |
optionType | JOptionPane.YES_NO_OPTION: knoppen Ja, Nee JOptionPane.YES_NO_CANCEL_OPTION: knoppen Ja, Nee, Annuleren |
Het resultaat van de methode is:
JOptionPane.YES_OPTION | de gebruiker heeft op ‘ja’ geklikt |
JOptionPane.NO_OPTION | de gebruiker heeft op 'nee' geklikt |
JOptionPane.CANCEL_OPTION | de gebruiker heeft op 'Annuleren' geklikt |
JOptionPane.CLOSED_OPTION | de gebruiker heeft het venster gesloten |
Hier is een voorbeeld:
import javax.swing.*;
public class confirm1 {
public static void main(String[] args) {
// toont bevestigingsvensters
int réponse;
affiche(JOptionPane.showConfirmDialog(null,"Voulez-vous continuer ?","Confirmation",JOptionPane.YES_NO_OPTION));
affiche(JOptionPane.showConfirmDialog(null,"Voulez-vous continuer ?","Confirmation",JOptionPane.YES_NO_CANCEL_OPTION));
}//hoofdpagina
private static void affiche(int réponse){
// geeft aan welk type antwoord er is ontvangen
switch(réponse){
case JOptionPane.YES_OPTION :
System.out.println("Oui");
break;
case JOptionPane.NO_OPTION :
System.out.println("Non");
break;
case JOptionPane.CANCEL_OPTION :
System.out.println("Annuler");
break;
case JOptionPane.CLOSED_OPTION :
System.out.println("Fermeture");
break;
}//-schakelaar
}//-display
}//sorteren
![]() | ![]() |
Op de console worden de meldingen Non en Annuler weergegeven.
5.3.4. Invoerveld
De klasse JOptionPane biedt ook de mogelijkheid om gegevens in te voeren met de methode showInputDialog. Ook hier zijn er verschillende overladen methoden. We laten er één zien:
static String | showInputDialog(Component parentComponent, Object message, String title, int messageType) |
De argumenten zijn dezelfde als die we al meerdere keren zijn tegengekomen. De methode retourneert de tekenreeks die door de gebruiker is ingevoerd. Hier is een voorbeeld:
import javax.swing.*;
public class input1 {
public static void main(String[] args) {
// invoer
System.out.println("Chaîne saisie ["+
JOptionPane.showInputDialog(null,"Quel est votre nom","Saisie du nom",JOptionPane.QUESTION_MESSAGE )
+ "]");
}//hand
}//klasse
Weergave van het invoerveld:

De weergave van de console:
5.4. Keuzelijsten
We gaan nu kijken naar een aantal vooraf gedefinieerde keuzelijsten in Java 2:
JFileChooser | keuzelijst waarmee een bestand in de bestandsstructuur kan worden geselecteerd |
JColorChooser | selectievenster waarmee een kleur kan worden gekozen |
5.4.1. Keuzelijst JFileChooser
We gaan de volgende applicatie bouwen:

De besturingselementen zijn als volgt:
Nr. | type | naam | rol |
0 | JScrollPane | jScrollPane1 | Scrollbare container voor tekstvak 1 |
1 | JTextArea zelf in de JScrollPane | txtTexte | door de gebruiker ingevoerde tekst of tekst die uit een bestand is geladen |
2 | JButton | btnSauvegarder | hiermee kan de tekst uit 1 in een tekstbestand worden opgeslagen |
3 | JButton | btnCharger | hiermee kan de inhoud van een tekstbestand in 1 worden geladen |
4 | JButton | btnEffacer | wist de inhoud van 1 |
Er wordt een niet-visuele besturingselement gebruikt: jFileChooser1. Dit wordt uit het palet met Swing-containers van JBuilder gehaald:

We plaatsen de component in het ontwerpvenster, maar buiten het formulier. Deze verschijnt in de lijst met componenten:

We geven nu de relevante programmacode weer om een totaalbeeld te krijgen:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.io.*;
public class dialogues extends JFrame {
// de onderdelen van het kader
JPanel contentPane;
JButton btnSauvegarder = new JButton();
JButton btnCharger = new JButton();
JButton btnEffacer = new JButton();
JScrollPane jScrollPane1 = new JScrollPane();
JTextArea txtTexte = new JTextArea();
JFileChooser jFileChooser1 = new JFileChooser();
// de bestandsfilters
javax.swing.filechooser.FileFilter filtreTxt = null;
//Het frame samenstellen
public dialogues() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
// overige initialisaties
moreInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
// moreInit
private void moreInit(){
// initialisaties bij het opbouwen van het venster
// filter *.txt
filtreTxt = new javax.swing.filechooser.FileFilter(){
public boolean accept(File f){
// wordt f geaccepteerd?
return f.getName().toLowerCase().endsWith(".txt");
}//accepteren
public String getDescription(){
// beschrijving van het filter
return "Fichiers Texte (*.txt)";
}//getDescription
};
// we voegen het filter toe
jFileChooser1.addChoosableFileFilter(filtreTxt);
// we willen ook het filter voor alle bestanden
jFileChooser1.setAcceptAllFileFilterUsed(true);
// we stellen de startmap van de map FileChooser in op de huidige map
jFileChooser1.setCurrentDirectory(new File("."));
}
//De component initialiseren
private void jbInit() throws Exception {
.......................
}
//Vervangen, zodat we kunnen afsluiten wanneer het venster wordt gesloten
protected void processWindowEvent(WindowEvent e) {
......................
}
}
void btnCharger_actionPerformed(ActionEvent e) {
// een bestand selecteren met behulp van een object JFileChooser
// het initiële filter instellen
jFileChooser1.setFileFilter(filtreTxt);
// het selectievenster wordt weergegeven
int returnVal = jFileChooser1.showOpenDialog(this);
// heeft de gebruiker iets gekozen?
if(returnVal == JFileChooser.APPROVE_OPTION) {
// het bestand wordt in het tekstveld geplaatst
lireFichier(jFileChooser1.getSelectedFile());
}//if
}//btnCharger_actionPerformed
// lireFichier
private void lireFichier(File fichier){
// geeft de inhoud van het tekstbestand weer in het tekstveld
// het tekstveld wordt gewist
txtTexte.setText("");
// enkele gegevens
BufferedReader IN=null;
String ligne=null;
try{
// bestand openen in leesmodus
IN=new BufferedReader(new FileReader(fichier));
// het bestand wordt regel voor regel gelezen
while((ligne=IN.readLine())!=null){
txtTexte.append(ligne+"\n");
}//while
// bestand sluiten
IN.close();
}catch(Exception ex){
// er is een fout opgetreden
txtTexte.setText(""+ex);
}//catch
}
// wissen
void btnEffacer_actionPerformed(ActionEvent e) {
// het tekstvak wordt gewist
txtTexte.setText("");
}
// opslaan
void btnSauvegarder_actionPerformed(ActionEvent e) {
// de inhoud van het tekstvak wordt opgeslagen in een bestand
// het beginfilter instellen
jFileChooser1.setFileFilter(filtreTxt);
// het opslagselectievenster wordt weergegeven
int returnVal = jFileChooser1.showSaveDialog(this);
// heeft de gebruiker iets gekozen?
if(returnVal == JFileChooser.APPROVE_OPTION) {
// de inhoud van het tekstvak wordt naar het bestand geschreven
écrireFichier(jFileChooser1.getSelectedFile());
}//if
}
// lireFichier
private void écrireFichier(File fichier){
// schrijft de inhoud van het tekstvak naar een bestand
// enkele gegevens
PrintWriter PRN=null;
try{
// bestand openen om te schrijven
PRN=new PrintWriter(new FileWriter(fichier));
// de inhoud van het tekstvak wordt geschreven
PRN.print(txtTexte.getText());
// bestand sluiten
PRN.close();
}catch(Exception ex){
// er is een fout opgetreden
txtTexte.setText(""+ex);
}//opvang
}
We zullen geen commentaar geven op de code van de methoden btnEffacer_Click, lireFichier en écrireFichier, aangezien deze niets nieuws bevatten. We zullen ingaan op de klasse JFileChooser en het gebruik ervan. Deze klasse is complex, een soort „ingewikkeld kluwen”. We gebruiken hier alleen de volgende methoden:
addChoosableFilter(FileFilter) | stelt de bestandstypen vast die ter selectie worden aangeboden |
setAcceptAllFileFilterUsed(boolean) | geeft aan of het type „Alle bestanden” al dan niet ter selectie moet worden aangeboden |
File getSelectedFile() | het door de gebruiker gekozen bestand (File) |
int showSaveDialog() | methode die het selectievenster voor het opslaan weergeeft. Geeft een resultaat van het type int terug. De waarde jFileChooser.APPROVE_OPTION geeft aan dat de gebruiker een geldige keuze heeft gemaakt. Anders heeft hij de keuze geannuleerd of is er een fout opgetreden. |
setCurrentDirectory | om de startmap in te stellen van waaruit de gebruiker het bestandssysteem gaat verkennen |
setFileFilter(FileFilter) | om het actieve filter in te stellen |
De methode showSaveDialog geeft een selectievenster weer dat er ongeveer zo uitziet:

1 | een vervolgkeuzelijst die is opgebouwd met de methode addChoosableFilter. Deze bevat zogenaamde selectiefilters, vertegenwoordigd door de klasse FileFilter. Het is aan de ontwikkelaar om deze filters te definiëren en toe te voegen aan lijst 1. |
2 | huidige map, vastgesteld door de methode setCurrentDirectory indien deze methode is gebruikt; anders is de huidige map de map "Mijn documenten" onder Windows of de homedirectory onder Unix. |
3 | naam van het bestand dat is geselecteerd of rechtstreeks door de gebruiker is ingevoerd. Beschikbaar via de methode getSelectedFile() |
4 | Knoppen Opslaan/Annuleren. Als de knop Enregistrer wordt gebruikt, levert de methode showSaveDialog het resultaat jFileChooser.APPROVE_OPTION op |
Hoe worden de bestandsfilters van de vervolgkeuzelijst 1 samengesteld? De filters worden aan lijst 1 toegevoegd met behulp van de methode:
addChoosableFilter(FileFilter) | bepaalt welke bestandstypen ter selectie worden aangeboden |
van de klasse JFileChooser. Nu moeten we nog de klasse FileFilter leren kennen. Dit is in feite de klasse javax.swing.filechooser.FileFilter, die een abstracte klasse is, c.a.d. Een klasse die niet kan worden geïnstantieerd, maar alleen kan worden afgeleid. Deze is als volgt gedefinieerd:
FileFilter() | constructor |
boolean accept(File) | geeft aan of het bestand f al dan niet tot het filter behoort |
String getDescription() | tekststring met de beschrijving van het filter |
Laten we een voorbeeld nemen. We willen dat de vervolgkeuzelijst 1 een filter biedt om de bestanden *.txt te selecteren met de beschrijving "Tekstbestanden (*.txt)".
- we moeten een klasse maken die is afgeleid van de klasse FileFilter
- de boolean-methode accept(File f) gebruiken om de waarde true te retourneren als de bestandsnaam f eindigt op .txt
- gebruik de methode String getDescription() om de beschrijving "Tekstbestanden (*.txt)" terug te geven
Dit filter zou in onze applicatie als volgt kunnen worden gedefinieerd:
javax.swing.filechooser.FileFilter filtreTxt = new javax.swing.filechooser.FileFilter(){
public boolean accept(File f){
// wordt f geaccepteerd?
return f.getName().toLowerCase().endsWith(".txt");
}//geaccepteerd
public String getDescription(){
// filterbeschrijving
return "Fichiers Texte (*.txt)";
}//getDescription
};
Dit filter zou aan de lijst met filters van het object jFileChooser1 worden toegevoegd met de instructie:
Dit alles en enkele andere initialisaties worden uitgevoerd in de methode moreInit, die wordt uitgevoerd bij het aanmaken van het venster (zie het volledige programma hierboven). De code van de knop Sauvegarder is als volgt:
void btnSauvegarder_actionPerformed(ActionEvent e) {
// slaat de inhoud van het tekstvak op in een bestand
// het oorspronkelijke filter instellen
jFileChooser1.setFileFilter(filtreTxt);
// het opslagkeuzevenster wordt weergegeven
int returnVal = jFileChooser1.showSaveDialog(this);
// heeft de gebruiker iets gekozen?
if(returnVal == JFileChooser.APPROVE_OPTION) {
// de inhoud van het tekstvak wordt naar het bestand geschreven
écrireFichier(jFileChooser1.getSelectedFile());
}//if
}
De volgorde van de handelingen is als volgt:
- het actieve filter wordt ingesteld op *.txt, zodat de gebruiker bij voorkeur naar dit type bestanden kan zoeken. Het filter "Alle bestanden" is ook aanwezig. Dit is toegevoegd in de procedure moreInit. Er zijn dus twee filters.
- het selectievenster voor het opslaan wordt weergegeven. Hier hebben we geen controle meer, aangezien de gebruiker het selectievenster gebruikt om een bestand uit het bestandssysteem aan te wijzen.
- Wanneer de gebruiker het selectievenster verlaat, wordt de retourwaarde gecontroleerd om te zien of het tekstvak al dan niet moet worden opgeslagen. Zo ja, dan moet dit gebeuren in het bestand dat wordt verkregen via de methode getSelectedFile.
De code voor de knop „Laden“ lijkt sterk op de code voor de knop „Opslaan“.
void btnCharger_actionPerformed(ActionEvent e) {
// een bestand selecteren met behulp van een object JFileChooser
// het beginfilter instellen
jFileChooser1.setFileFilter(filtreTxt);
// het selectievenster weergeven
int returnVal = jFileChooser1.showOpenDialog(this);
// heeft de gebruiker iets geselecteerd?
if(returnVal == JFileChooser.APPROVE_OPTION) {
// het bestand wordt in het tekstveld geplaatst
lireFichier(jFileChooser1.getSelectedFile());
}//if
}//btnCharger_actionPerformed
Er zijn twee verschillen:
- om het bestandsselectievenster weer te geven, wordt de methode showOpenDialog gebruikt in plaats van de methode showSaveDialog. Het weergegeven selectievenster is vergelijkbaar met dat van de methode showSaveDialog.
- Als de gebruiker daadwerkelijk een bestand heeft geselecteerd, wordt de methode lireFichier aangeroepen in plaats van de methode écrireFichier.
5.4.1.1. Selectievenster JColorChooser en JFontChooser
We gaan verder met het vorige voorbeeld door twee nieuwe knoppen toe te voegen:

Nr. | type | naam | rol |
6 | JButton | btnCouleur | om de kleur van de tekens van TextBox in te stellen |
7 | JButton | btnPolice | om het lettertype van TextBox in te stellen |
De component JColorChooser, waarmee een kleurselectievenster kan worden weergegeven, is te vinden in de lijst met Swing-componenten van JBuilder:

We plaatsen deze component in het ontwerpvenster, maar buiten het formulier. Hij is niet zichtbaar in het formulier, maar staat wel in de lijst met componenten van het venster:

De klasse JColorChooser is heel eenvoudig. We openen het kleurenkeuzevenster met de methode int showDialog:
static Color | showDialog(Component component, String title, Color initialColor) |
Component component | de bovenliggende component van het selectievenster, meestal een venster JFrame |
String title | de titel in de titelbalk van het selectievenster |
Kleur intialColor | kleur die aanvankelijk in het selectievenster is geselecteerd |
Als de gebruiker een kleur kiest, retourneert de methode een kleur; anders de waarde null. De code voor de knop Couleur is als volgt:
void btnCouleur_actionPerformed(ActionEvent e) {
// een tekstkleur kiezen met behulp van de component JColorChooser
Color couleur;
if((couleur=jColorChooser1.showDialog(this,"Choix d'une couleur",Color.BLACK))!=null){
// de kleur van de tekens in het tekstvak instellen
txtTexte.setForeground(couleur);
}//if
}
De klasse Color is gedefinieerd in java.awt.Color. Daarin zijn diverse constanten gedefinieerd, waaronder Color.BLACK voor de kleur zwart. Het weergegeven selectievenster ziet er als volgt uit

Vreemd genoeg biedt de Swing-bibliotheek geen klasse om een lettertype te selecteren. Gelukkig zijn er de Java-bronnen op internet. Door te zoeken op het trefwoord „JFontChooser”, wat een mogelijke naam voor een dergelijke klasse lijkt, vinden we er meerdere. In het volgende voorbeeld gaan we JBuilder zo configureren dat het pakketten gebruikt die niet in de oorspronkelijke configuratie waren voorzien.
Het opgehaalde pakket heet swingextras.jar en is geplaatst in de map <jdk>\jre\lib\perso, waarbij <jdk> verwijst naar de installatiemap van de JDK die door JBuilder wordt gebruikt. Het had ook ergens anders kunnen worden geplaatst.
![]() | ![]() |
Laten we eens kijken naar de inhoud van het pakket SwingExtras.jar:

Daarin zit de Java-broncode van de componenten die in het pakket worden aangeboden. Ook de klassen zelf zijn erin te vinden:

Uit dit archief blijkt dat de klasse JFontChooser in werkelijkheid com.lamatek.swingextras.JFontChooser heet. Als we de volledige naam niet willen schrijven, moeten we aan het begin van het programma het volgende schrijven:
Hoe zullen de compiler en de Java-virtuele machine dit nieuwe pakket vinden? In het geval van direct gebruik van JDK is dit al uitgelegd en kan de lezer de uitleg terugvinden in de paragraaf over Java-pakketten. Hier beschrijven we de methode die moet worden gebruikt met JBuilder. De pakketten worden geconfigureerd in het menu Opties/JDK configureren:

1 | Met de knop Modifier (1) kun je aan JBuilder aangeven welk JDK je wilt gebruiken. In dit voorbeeld had JBuilder de versie 1.3.1 van JDK meegebracht. Toen JDK 1.4 uitkwam, werd deze apart van JBuilder geïnstalleerd en werd de knop Modifier gebruikt om aan JBuilder aan te geven datvoortaan JDK 1.4 te gebruiken door de installatiemap van deze laatste aan te geven |
2 | basismap van JDK, die momenteel door JBuilder wordt gebruikt |
3 | lijst met Java-archieven (.jar) die door JBuilder worden gebruikt. Er kunnen andere worden toegevoegd met de knop Ajouter (4) |
4 | Met de knop Ajouter (4) kun je nieuwe pakketten toevoegen die JBuilder zowel voor het compileren als voor het uitvoeren van programma's zal gebruiken. We hebben deze knop hier gebruikt om het pakket SwingExtras.jar (5) toe te voegen |
Nu is JBuilder correct geconfigureerd om de klasse JFontChooser te kunnen gebruiken. We zouden echter toegang moeten hebben tot de definitie van deze klasse om deze correct te kunnen gebruiken. Het archief swingextras.jar bevat HTML-bestanden die we zouden kunnen extraheren om ze te gebruiken. Dat is echter niet nodig. De Java-documentatie die in de .jar-bestanden is opgenomen, is rechtstreeks toegankelijk vanuit JBuilder. Hiervoor moet het tabblad Documentation (6) hierboven worden geconfigureerd. Er verschijnt dan het volgende nieuwe venster:

Met de knop Ajouter kunnen we aangeven dat het bestand SwingExtras.jar moet worden doorzocht op documentatie. Nadat deze instelling is bevestigd, zien we dat we inderdaad toegang hebben tot de documentatie van SwingExtras.jar. Dit biedt verschillende voordelen:
- als we beginnen met het schrijven van de importinstructie
zullen we zien dat JBuilder ons hulp biedt:

Het pakket com.lamatek is inderdaad gevonden.
- Laten we nu eens kijken naar het volgende programma:
Als we F1 invoeren op het trefwoord JFontChooser, krijgen we hulp over deze klasse:

In de statusbalk 1 zien we dat er inderdaad een HTML-bestand uit het pakket swingextras.jar wordt gebruikt. Het hierboven gegeven voorbeeld is duidelijk genoeg om de code voor de knop Police in onze applicatie te kunnen schrijven:
void btnPolice_actionPerformed(ActionEvent e) {
// een lettertype kiezen met behulp van de component JFontChooser
jFontChooser1 = new JFontChooser(new Font("Arial", Font.BOLD, 12));
if (jFontChooser1.showDialog(this, "Choix d'une police") == JFontChooser.ACCEPT_OPTION) {
// het lettertype van de tekst in het tekstvak wijzigen
txtTexte.setFont(jFontChooser1.getSelectedFont());
}//if
}
Het selectievenster dat door de bovenstaande methode showDialog wordt weergegeven, ziet er als volgt uit:

5.5. De grafische toepassing IMPOTS
We pakken de applicatie IMPOTS er weer bij, die we al twee keer hebben behandeld. We voegen er nu een grafische interface aan toe:

De besturingselementen zijn als volgt
nr. | type | naam | rol |
1 | JRadioButton | rdOui | aangevinkt indien gehuwd |
2 | JRadioButton | rdNon | aangevinkt indien ongehuwd |
3 | JSpinner | spinEnfants | aantal kinderen van de belastingplichtige Minimum=0, Maximum=20, Stapgrootte=1 |
4 | JTextField | txtSalaire | jaarsalaris van de belastingplichtige in F |
5 | JLabel | lblImpots | te betalen belastingbedrag |
6 | JTextField | txtStatus | veld voor statusmeldingen – kan niet worden gewijzigd |
Het menu ziet er als volgt uit:
hoofdoptie | secundaire optie | naam | rol |
Belastingen | |||
Initialiseren | mnuInitialiser | laadt de gegevens die nodig zijn voor de berekening uit een tekstbestand | |
Berekenen | mnuCalculer | berekent de te betalen belasting wanneer alle benodigde gegevens aanwezig en correct zijn | |
Wissen | mnuEffacer | zet het formulier terug in de oorspronkelijke staat | |
Afsluiten | mnuQuitter | sluit de applicatie af |
Werkingsregels
- het menu Calculer blijft uitgeschakeld zolang het salarisveld leeg is
- als bij het starten van de berekening blijkt dat het salaris onjuist is, wordt de fout gemeld:

Het programma staat hieronder. Het maakt gebruik van de klasse impots die in het hoofdstuk over klassen is aangemaakt. Een deel van de code die automatisch door JBuilder wordt gegenereerd, is hier niet weergegeven.
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.io.*;
import java.util.*;
import javax.swing.event.*;
public class frmImpots extends JFrame {
// de componenten van het venster
JPanel contentPane;
JMenuBar jMenuBar1 = new JMenuBar();
JMenu jMenu1 = new JMenu();
JMenuItem mnuInitialiser = new JMenuItem();
JMenuItem mnuCalculer = new JMenuItem();
JMenuItem mnuEffacer = new JMenuItem();
JMenuItem mnuQuitter = new JMenuItem();
JLabel jLabel1 = new JLabel();
JFileChooser jFileChooser1 = new JFileChooser();
JTextField txtStatus = new JTextField();
JRadioButton rdOui = new JRadioButton();
JRadioButton rdNon = new JRadioButton();
JLabel jLabel2 = new JLabel();
JLabel jLabel3 = new JLabel();
JTextField txtSalaire = new JTextField();
JLabel jLabel4 = new JLabel();
JLabel jLabel5 = new JLabel();
JLabel lblImpots = new JLabel();
JLabel jLabel7 = new JLabel();
ButtonGroup buttonGroup1 = new ButtonGroup();
JSpinner spinEnfants=null;
FileFilter filtreTxt=null;
// de attributen van de klasse
double[] limites=null;
double[] coeffr=null;
double[] coeffn=null;
impots objImpots=null;
//Het frame opbouwen
public frmImpots() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
// andere initialisaties
moreInit();
}
// formulier initialiseren
private void moreInit(){
// menu 'Berekenen' geblokkeerd
mnuCalculer.setEnabled(false);
// invoervelden geblokkeerd
txtSalaire.setEditable(false);
txtSalaire.setBackground(Color.WHITE);
// statusveld
txtStatus.setBackground(Color.WHITE);
// spinner 'Kinderen' – tussen 0 en 20 kinderen
spinEnfants=new JSpinner(new SpinnerNumberModel(0,0,20,1));
spinEnfants.setBounds(new Rectangle(137,60,40,27));
contentPane.add(spinEnfants);
// filter *.txt voor de keuzelijst
filtreTxt = new javax.swing.filechooser.FileFilter(){
public boolean accept(File f){
// wordt 'f' geaccepteerd?
return f.getName().toLowerCase().endsWith(".txt");
}//accepteren
public String getDescription(){
// beschrijving van het filter
return "Fichiers Texte (*.txt)";
}//getDescription
};
// we voegen het filter *.txt toe
jFileChooser1.addChoosableFileFilter(filtreTxt);
// we willen ook het filter voor alle bestanden
jFileChooser1.setAcceptAllFileFilterUsed(true);
// we stellen de startmap van de map in FileChooser
jFileChooser1.setCurrentDirectory(new File("."));
}//moreInit
//De component initialiseren
private void jbInit() throws Exception {
................
}
//Vervangen, zodat we de toepassing kunnen afsluiten wanneer het venster wordt gesloten
protected void processWindowEvent(WindowEvent e) {
.....................
}
void mnuQuitter_actionPerformed(ActionEvent e) {
// we verlaten de applicatie
System.exit(0);
}
void mnuInitialiser_actionPerformed(ActionEvent e) {
// het gegevensbestand wordt geladen
// dat we selecteren met het selectievenster JFileChooser1
jFileChooser1.setFileFilter(filtreTxt);
if (jFileChooser1.showOpenDialog(this)!=JFileChooser.APPROVE_OPTION)
return;
// het geselecteerde bestand wordt verwerkt
try{
// gegevens lezen
lireFichier(jFileChooser1.getSelectedFile());
// het belastingobject aanmaken
objImpots=new impots(limites,coeffr,coeffn);
// bevestiging
txtStatus.setText("Données chargées");
// het salaris kan worden gewijzigd
txtSalaire.setEditable(true);
// geen wijzigingen meer mogelijk
mnuInitialiser.setEnabled(false);
}catch(Exception ex){
// probleem
txtStatus.setText("Erreur : " + ex.getMessage());
// einde
return;
}//catch
}
private void lireFichier(File fichier) throws Exception {
// de gegevenstabellen
ArrayList aLimites=new ArrayList();
ArrayList aCoeffR=new ArrayList();
ArrayList aCoeffN=new ArrayList();
String[] champs=null;
// bestand openen in leesmodus
BufferedReader IN=new BufferedReader(new FileReader(fichier));
// het bestand wordt regel voor regel gelezen
// ze hebben de vorm limiet coeffr coeffn
String ligne=null;
int numLigne=0; // huidige regelnummer
while((ligne=IN.readLine())!=null){
// nog een regel
numLigne++;
// de regel wordt opgesplitst in velden
champs=ligne.split("\\s+");
// 3 velden?
if(champs.length!=3)
throw new Exception("ligne " + numLigne + "erronée dans fichier des données");
// we halen de drie velden op
aLimites.add(champs[0]);
aCoeffR.add(champs[1]);
aCoeffN.add(champs[2]);
}//while
// bestand sluiten
IN.close();
// gegevens overbrengen naar begrensde tabellen
int n=aLimites.size();
limites=new double[n];
coeffr=new double[n];
coeffn=new double[n];
for(int i=0;i<n;i++){
limites[i]=Double.parseDouble((String)aLimites.get(i));
coeffr[i]=Double.parseDouble((String)aCoeffR.get(i));
coeffn[i]=Double.parseDouble((String)aCoeffN.get(i));
}//for
}
void mnuCalculer_actionPerformed(ActionEvent e) {
// berekening van de belasting
// looncontrole
int salaire=0;
try{
salaire=Integer.parseInt(txtSalaire.getText().trim());
if(salaire<0) throw new Exception();
}catch (Exception ex){
// foutmelding
txtStatus.setText("Salaire incorrect. Recommencez");
// focus op foutief veld
txtSalaire.requestFocus();
// terug naar de interface
return;
}
// aantal kinderen
Integer InbEnfants=(Integer)spinEnfants.getValue();
// belastingberekening
lblImpots.setText(""+objImpots.calculer(rdOui.isSelected(),InbEnfants.intValue(),salaire));
// statusbericht wissen
txtStatus.setText("");
}
void txtSalaire_caretUpdate(CaretEvent e) {
// het salaris is gewijzigd – het menu ‘Berekenen’ wordt bijgewerkt
mnuCalculer.setEnabled(! txtSalaire.getText().trim().equals(""));
}
void mnuEffacer_actionPerformed(ActionEvent e) {
// formulier leegmaken
rdNon.setSelected(true);
spinEnfants.getModel().setValue(new Integer(0));
txtSalaire.setText("");
mnuCalculer.setEnabled(false);
lblImpots.setText("");
}
}
We hebben hier een component gebruikt die pas vanaf JDK 1.4 beschikbaar is, namelijk de JSpinner. Het is een incrementor, waarmee de gebruiker hier het aantal onderliggende elementen kan instellen. Deze Swing-component was niet beschikbaar in de Swing-componentbalk van JBuilder 6, die voor de test werd gebruikt. Dit belet het gebruik ervan echter niet, ook al is het iets ingewikkelder dan bij de componenten die in de componentbalk beschikbaar zijn. De component JSpinner kan namelijk tijdens het ontwerpen niet op het formulier worden geplaatst. Dit moet tijdens de uitvoering gebeuren. Laten we eens kijken naar de code die dit doet:
// spinner 'Kinderen' – voer een aantal tussen 0 en 20 kinderen in
spinEnfants=new JSpinner(new SpinnerNumberModel(0,0,20,1));
spinEnfants.setBounds(new Rectangle(137,60,40,27));
contentPane.add(spinEnfants);
De eerste regel maakt de component JSpinner aan. Deze component kan voor verschillende doeleinden worden gebruikt, niet alleen als een integer-incrementor zoals hier. Het argument van de constructor JSpinner is hier een sjabloon voor een getalopbouwer die vier parameters accepteert (waarde, min, max, increment). De component heeft de volgende vorm:
![]()
valeur | beginstand die in de component wordt weergegeven |
min | minimale waarde die in de component kan worden weergegeven |
max | maximale waarde die in de component kan worden weergegeven |
incrément | stapgrootte van de weergegeven waarde bij gebruik van de pijltjes omhoog/omlaag van de component |
De waarde van de component wordt verkregen via de methode getValue, die een type Object retourneert. Vandaar enkele typeconversies om het benodigde gehele getal te verkrijgen:
// aantal kinderen
Integer InbEnfants=(Integer)spinEnfants.getValue();
// belastingberekening
lblImpots.setText(""+objImpots.calculer(rdOui.isSelected(),
InbEnfants.intValue(),salaire));
Zodra de component JSpinner is gedefinieerd, wordt deze in het venster geplaatst:
Allereerst moet de gebruiker de menuoptie Initialiser gebruiken, die een object impots aanmaakt met de constructor
van de klasse impots. Ter herinnering: deze klasse is als voorbeeld gedefinieerd in het hoofdstuk over klassen. Raadpleeg dit hoofdstuk indien nodig. De drie tabellen die de constructor nodig heeft, worden gevuld op basis van de inhoud van een tekstbestand met de volgende indeling:
12620.0 | 0 | 0 |
13190 | 0,05 | 631 |
15640 | 0,1 | 1290,5 |
24.740 | 0,15 | 2072,5 |
31810 | 0,2 | 3309,5 |
39.970 | 0,25 | 4900 |
48360 | 0,3 | 6898,5 |
55790 | 0,35 | 9316,5 |
92970 | 0,4 | 12106 |
127860 | 0,45 | 16754,5 |
151250 | 0,50 | 23147,5 |
172.040 | 0,55 | 30710 |
195.000 | 0,60 | 39312 |
0 | 0,65 | 49062 |
Elke regel bestaat uit drie getallen, gescheiden door ten minste één spatie. Dit tekstbestand wordt door de gebruiker geselecteerd met behulp van een component JFileChooser. Zodra het object van het type impots is aangemaakt, hoeft de gebruiker alleen nog maar de drie benodigde gegevens in te voeren: gehuwd of ongehuwd, aantal kinderen, jaarsalaris, en vervolgens de methode calculer van de klasse impots aan te roepen. Deze handeling kan meerdere keren worden herhaald. Het object van het type impots wordt slechts één keer aangemaakt, namelijk bij het gebruik van de optie Initialiser.
5.6. Applets schrijven
5.6.1. Inleiding
Wanneer men een applicatie met een grafische gebruikersinterface heeft geschreven, is het vrij eenvoudig om deze om te zetten naar applet. Deze wordt opgeslagen op computer A en kan via een webbrowser vanaf computer B via het internet worden gedownload. De oorspronkelijke applicatie wordt zo gedeeld door talrijke gebruikers en dat is het belangrijkste voordeel van het omzetten van een applicatie in een applet. Niet elke applicatie kan echter op deze manier worden omgezet: om de gebruiker die een applet in zijn browser gebruikt niet te hinderen, is de omgeving van de applet aan beperkingen onderworpen:
- een applet kan niet lezen of schrijven op de harde schijf van de gebruiker
- ze kan alleen communiceren met de computer van waaruit ze door de browser is gedownload.
Dit zijn strenge beperkingen. Ze houden bijvoorbeeld in dat een applicatie die informatie uit een bestand of een database moet lezen, deze moet opvragen via een tussenliggende applicatie op de server van waaruit ze is gedownload.
De algemene structuur van een eenvoudige webtoepassing is als volgt:

- de client vraagt een document HTML op bij de webserver, doorgaans via een browser. Dit document kan een applet bevatten die functioneert als een zelfstandige grafische applicatie binnen het document HTML dat door de browser van de client wordt weergegeven.
- Deze applet heeft toegang tot gegevens, maar alleen tot gegevens die zich op de webserver bevinden. De applet heeft geen toegang tot de bronnen van de clientcomputer waarop deze wordt uitgevoerd, noch tot die van andere computers in het netwerk, behalve de computer van waaruit deze is gedownload.
5.6.2. De klasse JApplet
5.6.2.1. Définition
Een applicatie kan via een webbrowser worden gedownload als het een instantie is van de klasse java.applet.Applet of van de klasse javax.swing.JApplet. Deze laatste is afgeleid van de eerste, die op haar beurt is afgeleid van de klasse Panel, die zelf is afgeleid van de klasse Container. Een instantie van Applet of JApplet, die van het type container is, kan dus componenten (Component) bevatten, zoals knoppen, selectievakjes, lijsten, … Hieronder volgen enkele aanwijzingen over de functie van de verschillende methoden:
Methode | Functie |
public void destroy(); | vernietigt de Applet-instantie |
public AppletContext getAppletContext(); | haalt de uitvoeringscontext van de applet op (het document HTML waarin deze zich bevindt, andere applets in hetzelfde document, …) |
public String getAppletInfo(); | geeft een tekenreeks terug met informatie over de applet |
public AudioClip getAudioClip(URL url); | laadt het audiobestand dat wordt gespecificeerd door URL |
public AudioClip getAudioClip(URL url, String name); | laadt het audiobestand dat wordt gespecificeerd door URL/name |
public URL getCodeBase(); | geeft de URL van de applet weer |
public URL getDocumentBase(); | geeft de URL van het document HTML weer dat de applet bevat |
public Image getImage(URL url); | haalt de afbeelding op die wordt gespecificeerd door URL |
public Image getImage(URL url, String name); | haalt de afbeelding op die wordt gespecificeerd door URL/name |
public String getParameter(String name); | haalt de waarde op van de parameter name die is opgenomen in de tag <applet> van het document HTML waarin de applet is opgenomen. |
public void init(); | deze methode wordt door de browser aangeroepen bij de eerste start van de applet |
public boolean isActive(); | status van de applet |
public void play(URL url); | speelt het geluidsbestand af dat wordt gespecificeerd door URL |
public void play(URL url, String name); | speelt het geluidsbestand af dat wordt gespecificeerd door UR/name |
public void resize(Dimension d); | stelt de afmetingen van het appletvenster in |
public void resize(int width, int height); | idem |
public final void setStub(AppletStub stub); | |
public void showStatus(String msg); | plaatst een bericht in de statusbalk van de applet |
public void start(); | deze methode wordt door de browser aangeroepen telkens wanneer het document met de applet wordt weergegeven |
public void stop(); | deze methode wordt door de browser aangeroepen telkens wanneer het document met de applet wordt verlaten ten gunste van een ander document (de gebruiker schakelt over van URL naar een ander document) |
De klasse JApplet heeft enkele verbeteringen aangebracht aan de klasse Applet, met name de mogelijkheid om componenten JMenuBar en c.a.d te bevatten. in de menu's, wat niet mogelijk was met de klasse Applet.
5.6.2.2. Een applet uitvoeren: de methoden init, start en stop
Wanneer een browser een applet laadt, roept hij drie methoden van de applet aan:
init | Deze methode wordt aangeroepen bij het eerste laden van de applet. Hierin worden dus de initialisaties opgenomen die nodig zijn voor de toepassing. |
start | Deze methode wordt aangeroepen telkens wanneer het document dat de applet bevat het actieve document van de browser wordt. Wanneer een gebruiker dus een applet laadt, worden de methoden init en start in deze volgorde uitgevoerd. Wanneer hij het document verlaat om een ander document te bekijken, wordt de methode stop uitgevoerd. Wanneer hij later terugkeert naar dit document, wordt de methode start uitgevoerd. |
stop | Deze methode wordt aangeroepen telkens wanneer de gebruiker het document met de applet verlaat. |
Voor veel applets is alleen de methode init nodig. De methoden start en stop zijn alleen nodig als de toepassing taken (threads) start die parallel en continu draaien, vaak zonder dat de gebruiker dit merkt. Wanneer de gebruiker het document verlaat, verdwijnt het zichtbare deel van de toepassing, maar deze achtergrondtaken blijven doorwerken. Dit is vaak overbodig. We maken dan gebruik van de aanroep van de browser naar de methode **stop om ze te stoppen. Als de gebruiker terugkeert naar het document, maken we gebruik van de aanroep van de browser naar de methode **start om ze opnieuw te starten.
Laten we bijvoorbeeld een applet nemen met een klok in de grafische interface. Deze wordt onderhouden door een achtergrondtaak (thread). Wanneer de gebruiker in de browser de pagina van de applet verlaat, heeft het geen zin om de klok te blijven onderhouden, aangezien deze onzichtbaar is geworden: in de stop-methode van de applet stoppen we de thread die de klok beheert. In de start-methode wordt deze opnieuw gestart, zodat de gebruiker, wanneer hij terugkeert naar de appletpagina, een klok ziet die de juiste tijd aangeeft.
5.6.3. Omzetting van een grafische applicatie naar een applet
We gaan er hier vanuit dat deze omzetting mogelijk is, dat wil zeggen dat deze voldoet aan de uitvoeringsbeperkingen van applets. Een applicatie wordt gestart via de methode main van een van de klassen:
Een dergelijke toepassing wordt als volgt omgezet in een applet:
import java.applet.JApplet;
…
public class application extends JApplet{
…
public void init(){
…
}
…
}// einde klas
Let op het volgende:
- de klasse application is nu afgeleid van de klasse JApplet
- de methode main wordt vervangen door de methode init.
Ter illustratie komen we terug op een eerder besproken toepassing: het beheer van lijsten.

De componenten van dit venster zijn als volgt:
nr. | type | naam | functie |
1 | JTextField | txtSaisie | invoerveld |
2 | JList | jList1 | lijst in een container jScrollPane1 |
3 | JList | jList2 | lijst in een container jScrollPane2 |
4 | JButton | cmd1To2 | verplaatst de geselecteerde items van lijst 1 naar lijst 2 |
5 | JButton | cmd2To1 | doet het omgekeerde |
6 | JButton | cmdRaz1 | maak lijst 1 leeg |
7 | JButton | cmdRaz2 | lijst 2 leegmaken |
De structuur van de applicatie zag er als volgt uit:
public class interfaceAppli extends JFrame {
JPanel contentPane;
JLabel jLabel1 = new JLabel();
JLabel jLabel2 = new JLabel();
JLabel jLabel3 = new JLabel();
JTextField txtSaisie = new JTextField();
JButton cmd1To2 = new JButton();
JButton cmd2To1 = new JButton();
DefaultListModel v1=new DefaultListModel();
DefaultListModel v2=new DefaultListModel();
JList jList1 = new JList(v1);
JList jList2 = new JList(v2);
JScrollPane jScrollPane1 = new JScrollPane();
JScrollPane jScrollPane2 = new JScrollPane();
JButton cmdRaz1 = new JButton();
JButton cmdRaz2 = new JButton();
JLabel jLabel4 = new JLabel();
/**Het kader opbouwen*/
public interfaceAppli() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}//interfaceAppli
/**De component initialiseren*/
private void jbInit() throws Exception {
...
txtSaisie.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
txtSaisie_actionPerformed(e);
}
});
...
// Jlist1 wordt in de container geplaatst jScrollPane1
jScrollPane1.getViewport().add(jList1, null);
// Jlist2 wordt in de container geplaatst jScrollPane2
jScrollPane2.getViewport().add(jList2, null);
...
}
/**Vervangen, zodat we kunnen afsluiten wanneer het venster wordt gesloten*/
protected void processWindowEvent(WindowEvent e) {
...
}
void txtSaisie_actionPerformed(ActionEvent e) {
.............
}//klasse
void cmdRaz1_actionPerformed(ActionEvent e) {
// lijst 1 leegmaken
v1.removeAllElements();
}//cmd Raz1
void cmdRaz2_actionPerformed(ActionEvent e) {
// lijst 2 leegmaken
v2.removeAllElements();
}///cmd Raz2
Om de klasse appli om te zetten in applet, moet u als volgt te werk gaan:
- pas de vorige klasse interfaceAppli zodanig aan dat deze niet langer afgeleid is van JFrame, maar van JApplet:
- verwijder de instructie die de titel van het venster JFrame vastlegt. Een applet JApplet heeft geen titelbalk
- Verander de constructor in een methode init en verwijder in deze methode de afhandeling van venstergebeurtenissen (WindowListener, ...). Een applet is een container die niet in grootte kan worden aangepast of gesloten.
/**Het kader opbouwen*/
public init() {
// enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}//interfaceAppli
- De methode processWindowEvent moet worden verwijderd of uitgecommentarieerd
/**Vervangen, zodat we kunnen afsluiten wanneer het venster gesloten is*/
//protected void processWindowEvent(WindowEvent e) {
// super.processWindowEvent(e);
// if (e.getID() == WindowEvent.WINDOW_CLOSING) {
// System.exit(0);
// }
// }
Ter illustratie geven we de volledige code van de applet, met uitzondering van het gedeelte dat automatisch wordt gegenereerd door JBuilder
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class interfaceAppli extends JApplet {
JPanel contentPane;
JLabel jLabel1 = new JLabel();
JLabel jLabel2 = new JLabel();
JLabel jLabel3 = new JLabel();
JTextField txtSaisie = new JTextField();
JButton cmd1To2 = new JButton();
JButton cmd2To1 = new JButton();
DefaultListModel v1=new DefaultListModel();
DefaultListModel v2=new DefaultListModel();
JList jList1 = new JList(v1);
JList jList2 = new JList(v2);
JScrollPane jScrollPane1 = new JScrollPane();
JScrollPane jScrollPane2 = new JScrollPane();
JButton cmdRaz1 = new JButton();
JButton cmdRaz2 = new JButton();
JLabel jLabel4 = new JLabel();
/**Het kader opbouwen*/
public void init() {
// enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}//interfaceAppli
/**De component initialiseren*/
private void jbInit() throws Exception {
//setIconImage(Toolkit.getDefaultToolkit().createImage(interfaceAppli.class.getResource("[Votre icône]")));
contentPane = (JPanel) this.getContentPane();
contentPane.setLayout(null);
this.setSize(new Dimension(400, 308));
// this.setTitle("JList");
jScrollPane1.setBounds(new Rectangle(37, 133, 124, 101));
jScrollPane2.setBounds(new Rectangle(232, 132, 124, 101));
.............
}
void txtSaisie_actionPerformed(ActionEvent e) {
// de ingevoerde tekst is gevalideerd
// de tekst wordt opgehaald zonder de spaties aan het begin en einde
String texte=txtSaisie.getText().trim();
// als deze leeg is, wordt deze genegeerd
if(texte.equals("")){
// foutmelding
JOptionPane.showMessageDialog(this,"Vous devez taper un texte",
"Erreur",JOptionPane.WARNING_MESSAGE);
// einde
return;
}//if
// als het niet leeg is, voegen we het toe aan de waarden in lijst 1
v1.addElement(texte);
// en het invoerveld wordt leeggemaakt
txtSaisie.setText("");
}
void cmd1To2_actionPerformed(ActionEvent e) {
// de geselecteerde elementen uit lijst 1 overbrengen naar lijst 2
transfert(jList1,jList2);
}//cmd1To2
private void transfert(JList L1, JList L2){
// de geselecteerde elementen uit lijst 1 overbrengen naar lijst 2
// de indexen van de geselecteerde elementen worden opgehaald uit L1
int[] indices=L1.getSelectedIndices();
// moet er iets gebeuren?
if (indices.length==0) return;
// de waarden worden opgehaald uit L1
DefaultListModel v1=(DefaultListModel)L1.getModel();
// en die uit L2
DefaultListModel v2=(DefaultListModel)L2.getModel();
for(int i=indices.length-1;i>=0;i--){
// de in L1 geselecteerde waarden worden toegevoegd aan L2
v2.addElement(v1.elementAt(indices[i]));
// de elementen van L1 die naar L2 zijn gekopieerd, moeten uit L1 worden verwijderd
v1.removeElementAt(indices[i]);
}//voor
}//overdracht
private void affiche(String message){
// geeft een bericht weer
JOptionPane.showMessageDialog(this,message,
"Suivi",JOptionPane.INFORMATION_MESSAGE);
}// geeft weer
void cmd2To1_actionPerformed(ActionEvent e) {
// overdracht van de geselecteerde elementen in jList2 naar jList1
transfert(jList2,jList1);
}//cmd2TO1
void cmdRaz1_actionPerformed(ActionEvent e) {
// lijst 1 leegmaken
v1.removeAllElements();
}//cmd Raz1
void cmdRaz2_actionPerformed(ActionEvent e) {
// lijst 2 leegmaken
v2.removeAllElements();
}//cmd Raz2
}//klasse
De broncode van deze applet kan worden gecompileerd. Dat doen we hier met JDK, zonder JBuilder.
E:\data\serge\Jbuilder\interfaces\JApplets\1>javac.bat interfaceAppli.java
E:\data\serge\Jbuilder\interfaces\JApplets\1>dir
12/06/2002 16:40 6 148 interfaceAppli.java
12/06/2002 16:41 527 interfaceAppli$1.class
12/06/2002 16:41 525 interfaceAppli$2.class
12/06/2002 16:41 525 interfaceAppli$3.class
12/06/2002 16:41 525 interfaceAppli$4.class
12/06/2002 16:41 525 interfaceAppli$5.class
12/06/2002 16:41 4 759 interfaceAppli.class
De applicatie kan worden getest met het programma AppletViewer van JDK, waarmee applets of een browser kunnen worden uitgevoerd. Hiervoor moet het document HTML appli.htm worden aangemaakt, waarin de volgende applet is opgenomen:
<html>
<head>
<title>listes swing</title>
</head>
<body>
<applet
code="interfaceAppli.class"
width="400"
height="300">
</applet>
</body>
</html>
Dit is een standaard HTML-document, afgezien van de aanwezigheid van de applet-tag. Deze is gebruikt met drie parameters:
code="interfaceAppli.class" | naam van de gecompileerde JAVA-klasse die moet worden geladen om de applet uit te voeren |
width="400" | breedte van het applet-frame in het document |
height="300" | hoogte van het applet-frame in het document |
Zodra het bestand appli.htm is opgeslagen, kan het worden geladen met het programma appletviewer van JDK of met een browser. Typ in een DOS-venster de volgende opdracht in de map van het bestand appli.htm:
appletviewer appli.htm
Hierbij wordt ervan uitgegaan dat de map met het uitvoerbare bestand appletviewer.exe zich in de map PATH van het DOS-venster bevindt; anders zou het volledige pad naar het uitvoerbare bestand appletviewer.exe moeten worden opgegeven. Het volgende venster verschijnt:

We stoppen de uitvoering van de applet met de optie Applet/Quitter. Laten we de applet nu testen met een browser. Deze moet een Java 2-virtuele machine gebruiken om de Swing-componenten te kunnen weergeven. Tot voor kort (2001) leverde deze beperking problemen op, omdat Sun JDK-bestanden produceerde die door browserontwikkelaars pas met grote vertraging werden ondersteund. Uiteindelijk heeft Sun een einde gemaakt aan dit obstakel door gebruikers een applicatie ter beschikking te stellen met de naam „Java-plugin”, waarmee de browsers Internet Explorer en Netscape Navigator gebruik kunnen maken van de allernieuwste door Sun geproduceerde JRE (JRE = Java Runtime Environment). De volgende tests zijn uitgevoerd met IE 5.5, uitgerust met de Java 1.4-plugin.
Een eerste manier om de applet interfaceAppli.class te testen, is door het bestand HTML appli.htm rechtstreeks in de browser te laden door erop te dubbelklikken. De browser geeft dan de pagina HTML en de bijbehorende applet weer zonder tussenkomst van een webserver:

Uit URL (1) blijkt dat het bestand rechtstreeks in de browser is geladen. In het volgende voorbeeld is het bestand appli.htm opgevraagd bij een Apache-webserver die draait op poort 81 van de lokale machine:

5.6.4. De opmaakoptie <applet> in een HTML-document
We hebben gezien dat in een document met de naam HTML naar de applet werd verwezen via de opmaakcode (tag) <applet>. Deze code kan verschillende parameters hebben:
<applet
code=
width=
height=
codebase=
align=
hspace=
vspace=
alt=
>
<param name1=nom1 value=val1>
<param name2=nom2 value=val2>
texte
>
</applet>
De betekenis van de parameters is als volgt:
Parameter | Betekenis |
code | verplicht - naam van het uit te voeren .class-bestand |
width | verplicht - breedte van de applet in het document |
height | verplicht - hoogte … |
codebase | optioneel - URL van de map waarin de uit te voeren applet zich bevindt. Als codebase niet is opgegeven, wordt de applet gezocht in de map van het HTML-document dat ernaar verwijst |
align | optioneel - positionering (LEFT, RiGHT, CENTER) van de applet in het document |
hspace | optioneel - horizontale marge rondom de applet, uitgedrukt in pixels |
vspace | optioneel - verticale marge rondom de applet, uitgedrukt in pixels |
alt | optioneel - tekst die in plaats van de applet wordt weergegeven als de browser deze niet kan laden |
param | optioneel - parameter die aan de applet wordt doorgegeven en de naam (name) en waarde (value) ervan specificeert. De applet kan de waarde van de parameter naam1 ophalen via val1=getParameter("naam1") Er kunnen zoveel parameters worden gebruikt als men wil |
texte | optioneel – wordt weergegeven door elke browser die geen applet kan uitvoeren, bijvoorbeeld omdat deze geen Java-virtuele machine heeft. |
Laten we een voorbeeld nemen om het doorgeven van parameters aan een applet te illustreren:
<html>
<head>
<title>paramètres applet</title>
</head>
<body>
<applet code="interfaceParams.class" width="400" height="300">
<param name="param1" value="val1">
<param name="param2" value="val2">
</applet>
</body>
</html>
De Java-code van de applet interfaceParams is gegenereerd zoals hierboven beschreven. We hebben een applicatie JBuilder gebouwd en vervolgens de hierboven genoemde aanpassingen doorgevoerd:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class interfaceParams extends JApplet {
JPanel contentPane;
JScrollPane jScrollPane1 = new JScrollPane();
JLabel jLabel1 = new JLabel();
DefaultListModel params=new DefaultListModel();
JList lstParams = new JList(params);
//Het kader opbouwen
public void init() {
// enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
// overige initialisaties
moreInit();
}
// initialisaties
public void moreInit(){
// geeft de waarden van de appletparameters weer
params.addElement("nom=param1 valeur="+getParameter("param1"));
params.addElement("nom=param2 valeur="+getParameter("param2"));
}//meer Init
//De component initialiseren
private void jbInit() throws Exception {
............
this.setSize(new Dimension(205, 156));
//this.setTitle("Instellingen van een applet");
jScrollPane1.setBounds(new Rectangle(19, 53, 160, 73));
............
}
}
De uitvoering met AppletViewer:

5.6.5. Toegang tot externe bronnen vanuit een applet
Veel applicaties moeten gebruikmaken van informatie in bestanden of databases. We hebben aangegeven dat een applet geen toegang heeft tot de bronnen van de machine waarop deze wordt uitgevoerd. Dit is een maatregel die op gezond verstand berust. Anders zou het immers voldoende zijn om een applet te schrijven om de harde schijf van degenen die de applet laden te „bespioneren”. De applet heeft echter wel toegang tot de bronnen van de server waarvan hij is gedownload, bijvoorbeeld bestanden. Dat gaan we nu bekijken.
5.6.5.1. De klasse URL
Elke Java-toepassing kan een bestand op een computer in het netwerk lezen dankzij de klasse java.net.URL (URL = Uniform Resource Locator). Een URL identificeert een bron op het netwerk, de computer waarop deze zich bevindt, evenals het protocol en de communicatiepoort die moeten worden gebruikt om deze op te halen, in de vorm:
protocol:poort//computer/bestand
Zo verwijst de URL http://www.ibm.com/index.html naar het bestand index.html op de machine www.ibm.com. Het is toegankelijk via het protocol http. De poort is niet gespecificeerd: de browser gebruikt poort 80, de standaardpoort voor de http-service.
Laten we enkele elementen van de klasse URL nader bekijken:
public URL(String spec) | maakt een instantie van URL aan op basis van een tekenreeks van het type "protocol:poort//machine/bestand" – genereert een uitzondering als de syntaxis van de tekenreeks niet overeenkomt met een URL |
public String getFile() | haalt het veld "bestand" op uit de tekenreeks "protocol:poort//machine/bestand" van de URL |
public String getHost() | maakt het mogelijk om het veld machine te verkrijgen uit de tekenreeks "protocol:poort//machine/bestand" van de URL |
public String getPort() | maakt het mogelijk om het veld 'poort' uit de tekenreeks "protocol:poort//machine/bestand" van de URL te verkrijgen |
public String getProtocol() | maakt het mogelijk om het veld 'protocol' uit de tekenreeks "protocol:poort//machine/bestand" van de URL te verkrijgen |
public URLConnection openConnection() | opent de verbinding met de externe machine getHost() op poort getPort() volgens het protocol getProtocol() om het bestand getFile() te lezen. Genereert een uitzondering als de verbinding niet kon worden geopend |
public final InputStream openStream() | afkorting voor openConnection().getInputStream(). Hiermee kan een invoerstroom worden verkregen waarmee de inhoud van het bestand getFile() kan worden gelezen. Er wordt een uitzondering gegenereerd als de stroom niet kon worden verkregen |
public String toString() | geeft de identiteit van de instantie van URL weer |
Er zijn hier twee methoden die voor ons van belang zijn:
- public URL(String spec) om het te verwerken bestand op te geven
- public final InputStream openStream() om het te verwerken
5.6.5.2. Een voorbeeld voor de commandoregel
We gaan een Java-programma schrijven, zonder grafische interface, dat de inhoud van een URL die als parameter wordt doorgegeven, op het scherm weergeeft. Een voorbeeld van een aanroep zou als volgt kunnen zijn:
Het programma is relatief eenvoudig:
import java.net.*; // voor de klasse URL
import java.io.*; // voor de streams
public class urlcontenu{
// geeft de inhoud weer van de als argument doorgegeven URL
// deze inhoud moet uit tekst bestaan om leesbaar te zijn
public static void main (String arg[]){
// controle van de argumenten
if(arg.length==0){
System.err.println("Syntaxe pg url");
System.exit(0);
}
try{
// aanmaken van de URL
URL url=new URL(arg[0]);
// inhoud lezen
try{
// aanmaken van de invoerstroom
BufferedReader is=new BufferedReader(new InputStreamReader(url.openStream()));
try{
// tekstregels in de invoerstroom lezen
String ligne;
while((ligne=is.readLine())!=null)
System.out.println(ligne);
} catch (Exception e){
System.err.println("Erreur lecture : " +e);
}
finally{
try { is.close(); } catch (Exception e) {}
}
} catch (Exception e){
System.err.println("Erreur openStream : " +e);
}
} catch (Exception e){
System.err.println("Erreur création URL : " +e);
}
}// einde main
}// einde klasse
Nadat is gecontroleerd of er inderdaad een argument is, wordt geprobeerd om hiermee een URL aan te maken:
// URL aanmaken
URL url=new URL(arg[0]);
Het aanmaken kan mislukken als het argument niet voldoet aan de syntaxis van de URL protocole:port//machine/fichier. Als we een syntactisch correcte URL hebben, proberen we een invoerstroom aan te maken waaruit we tekstregels kunnen lezen. De invoerstroom die wordt geleverd door een URL URL.openStream() levert een stroom van het type InputStream op, wat een tekengeoriënteerde stroom is: het lezen gebeurt teken voor teken en men moet zelf de regels samenstellen. Om tekstregels te kunnen lezen, moet de methode readLine van de klassen BufferedReader of DataInputStream.On worden gebruikt; hier is gekozen voor BufferedReader. Nu hoeven we alleen nog maar de stream InputStream van URL om te zetten in de stream BufferedReader. Dit doe je door een tussenstream InputStreamReader aan te maken:
BufferedReader is=new BufferedReader(new InputStreamReader(url.openStream()));
Het aanmaken van deze stream kan mislukken. We vangen de bijbehorende uitzondering op. Zodra we de stream hebben, hoeven we alleen nog maar de tekstregels eruit te lezen en deze op het scherm weer te geven.
String ligne;
while((ligne=is.readLine())!=null)
System.out.println(ligne);
Ook hier kan het inlezen een uitzondering veroorzaken die moet worden afgehandeld. Hier volgt een voorbeeld van de uitvoering van het programma, waarbij een lokale URL wordt aangevraagd:
E:\data\serge\Jbuilder\interfaces\JApplets\3>java urlcontenu http://localhost
<html>
<head>
<title>Bienvenue dans le Serveur Web personnel</title>
</head>
<body bgcolor="#FFFFFF" link="#0080FF" vlink="#0080FF"
topmargin="0" leftmargin="0">
<table border="0" cellpadding="0" cellspacing="0" width="100%"
bgcolor="#000000">
............
</table>
</center></div></td>
</tr>
</table>
</td>
</tr>
</table>
</body>
</html>
5.6.5.3. Een grafisch voorbeeld
De grafische interface ziet er als volgt uit:

Nummer | Naam | Type | Rol |
1 | txtURL | JTextField | URL te lezen |
2 | btnCharger | JButton | knop om het afspelen van URL te starten |
3 | JScrollPane1 | JScrollPane | schuifbalk |
4 | lstURL | JList | lijst met de inhoud van de opgevraagde URL |
Bij uitvoering krijgen we een resultaat dat vergelijkbaar is met dat van het consoleprogramma:

De relevante code van de applicatie is als volgt:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.net.*;
import java.io.*;
public class interfaceURL extends JFrame {
JPanel contentPane;
JLabel jLabel1 = new JLabel();
JTextField txtURL = new JTextField();
JButton btnCharger = new JButton();
JScrollPane jScrollPane1 = new JScrollPane();
DefaultListModel lignes=new DefaultListModel();
JList lstURL = new JList(lignes);
//Het frame opbouwen
public interfaceURL() {
..............
}
//De component initialiseren
private void jbInit() throws Exception {
..............
}
//Vervangen, zodat we kunnen afsluiten wanneer het venster wordt gesloten
protected void processWindowEvent(WindowEvent e) {
...................
}
void txtURL_caretUpdate(CaretEvent e) {
// stelt de status van de knop 'Laden' in
btnCharger.setEnabled(! txtURL.getText().trim().equals(""));
}
void btnCharger_actionPerformed(ActionEvent e) {
// geeft de inhoud van URL weer in de lijst
try{
afficherURL(txtURL.getText().trim());
}catch(Exception ex){
// foutmelding weergeven
JOptionPane.showMessageDialog(this,"Erreur : " + ex.getMessage(),"Erreur",JOptionPane.ERROR_MESSAGE);
}//try-catch
}
private void afficherURL(String strURL) throws Exception {
// geeft de inhoud van URL strURL weer in de lijst
// er wordt geen specifieke uitzondering afgehandeld. Ze worden gewoon doorgegeven
// aanmaken van het URL
URL url=new URL(strURL);
// aanmaken van de invoerstroom
BufferedReader IN=new BufferedReader(new InputStreamReader(url.openStream()));
// lezen van de tekstregels in de invoerstroom
String ligne;
while((ligne=IN.readLine())!=null)
lignes.addElement(ligne);
// de leesstroom sluiten
IN.close();
}
}
5.6.5.4. Een applet
De vorige grafische toepassing is omgezet in een applet, zoals al meerdere keren is uitgelegd. De applet is ingevoegd in een document HTML appliURL.htm:
<html>
<head>
<title>Applet lisant une URL</title>
</head>
<body>
<h1>Applet lisant une URL</h1>
<applet
code="appletURL.class"
width="400"
height="300"
>
</applet>
</body>
</html>

In het bovenstaande voorbeeld heeft de browser de URL http://localhost:81/Japplets/2/appliURL.htm opgevraagd bij een webserver apache die draait op poort 81. De applet werd vervolgens in de browser weergegeven. Daarin werd opnieuw het adres URL http://localhost:81/Japplets/2/appliURL.htm opgevraagd om te controleren of we inderdaad het bestand appliURL.htm kregen dat we hadden gemaakt. Laten we nu eens proberen een URL te laden die niet afkomstig is van de machine die de applet heeft geleverd (in dit geval localhost):

Het laden van het URL-bestand is geweigerd. Hier zien we opnieuw de beperking die aan applets is verbonden: ze hebben alleen toegang tot de netwerkbronnen van de computer van waaruit ze zijn gedownload. Er is een manier waarop de applet deze beperking kan omzeilen, namelijk door de netwerkverzoeken door te geven aan een serverprogramma op de computer van waaruit de applet is gedownload. Dit programma voert de netwerkverzoeken uit in plaats van de applet en stuurt de resultaten terug naar de applet. Dit wordt een relaisprogramma genoemd.
5.7. De applet IMPOTS
We gaan nu de grafische applicatie IMPOTS omzetten in een applet. Dit heeft een zeker voordeel: de applicatie wordt beschikbaar voor elke internetgebruiker die beschikt over een browser en een Java-plugin 1.4 (dankzij de component JSpinner). Onze applicatie wordt zo wereldwijd beschikbaar... Deze aanpassing vereist iets meer dan de inmiddels klassieke omzetting van grafische applicatie naar applet. De applicatie maakt gebruik van een menuoptie Initialiser die bedoeld is om de inhoud van een lokaal bestand te lezen. Maar als we ons een webapplicatie voorstellen, zien we dat dit schema niet meer opgaat:

Het is duidelijk dat de gegevens die de belastingtarieven definiëren op de webserver zullen staan en niet op elke afzonderlijke clientcomputer. Het bestand dat op de webserver moet worden gelezen, wordt hier in dezelfde map geplaatst als de applet en de optie Initialiser moet het daar ophalen. De voorgaande voorbeelden hebben laten zien hoe dit moet. Overigens werd voor het lokaal selecteren van het gegevensbestand een component JFileChooser gebruikt, die hier niet meer nodig is.
Het document HTML met de applet ziet er als volgt uit:
<html>
<head>
<title>Applet de calcul d'impôts</title>
</head>
<body>
<h2>Calcul d'impôts</h2>
<applet
code="appletImpots.class"
width="320"
height="270"
>
<param name="data" value="impots.txt">
Let op de parameter data, waarvan de waarde de naam is van het bestand dat de gegevens van de belastingtabel bevat. Het document HTML, de klasse appletImpots, de klasse impots en het bestand impots.txt bevinden zich allemaal in dezelfde map op de webserver:
E:\data\serge\web\JApplets\impots>dir
12/06/2002 13:24 247 impots.txt
13/06/2002 10:17 654 appletImpots$2.class
13/06/2002 10:17 653 appletImpots$3.class
13/06/2002 10:17 653 appletImpots$4.class
13/06/2002 10:17 651 appletImpots$5.class
13/06/2002 10:06 651 appletImpots$6.class
13/06/2002 10:17 8 655 appletImpots.class
13/06/2002 10:17 657 appletImpots$1.class
13/06/2002 10:24 286 appletImpots.htm
13/06/2002 10:17 1 305 impots.class
De code van de applet is als volgt (we hebben alleen de wijzigingen ten opzichte van de grafische toepassing gemarkeerd):
...........
import java.net.*;
import java.applet.Applet;
public class appletImpots extends JApplet {
// de componenten van het venster
JPanel contentPane;
............................
// de attributen van de klasse
double[] limites=null;
double[] coeffr=null;
double[] coeffn=null;
impots objImpots=null;
String urlDATA=null;
//Het frame opbouwen
public void init() {
//enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
// overige initialisaties
moreInit();
}
// formulier initialiseren
private void moreInit(){
// menu 'Berekenen' uitgeschakeld
mnuCalculer.setEnabled(false);
................
// de bestandsnaam van de belastingtabel wordt opgehaald
String nomFichier=getParameter("data");
// fout?
if(nomFichier==null){
// foutmelding
txtStatus.setText("Le paramètre data de l'applet n'a pas été initialisé");
// de optie Initialiseren wordt geblokkeerd
mnuInitialiser.setEnabled(false);
// einde
return;
}//if
// de URL van de gegevens wordt vastgelegd
urlDATA=getCodeBase()+"/"+nomFichier;
}//moreInit
//De component initialiseren
private void jbInit() throws Exception {
...................
}
void mnuQuitter_actionPerformed(ActionEvent e) {
// de applicatie afsluiten
System.exit(0);
}
void mnuInitialiser_actionPerformed(ActionEvent e) {
// het gegevensbestand laden
try{
// gegevens lezen
lireDATA();
// het object 'belastingen' aanmaken
objImpots=new impots(limites,coeffr,coeffn);
................
}
private void lireDATA() throws Exception {
// de gegevenstabellen
ArrayList aLimites=new ArrayList();
ArrayList aCoeffR=new ArrayList();
ArrayList aCoeffN=new ArrayList();
String[] champs=null;
// bestand openen in leesmodus
BufferedReader IN=new BufferedReader(new InputStreamReader(new URL(urlDATA).openStream()));
// het bestand wordt regel voor regel gelezen
....................
}
void mnuCalculer_actionPerformed(ActionEvent e) {
// de belasting berekenen
......................
}
void txtSalaire_caretUpdate(CaretEvent e) {
..........
}
void mnuEffacer_actionPerformed(ActionEvent e) {
...............
}
}
We bespreken hier alleen de wijzigingen die voortvloeien uit het feit dat het te lezen gegevensbestand zich nu op een externe machine bevindt in plaats van op een lokale machine:
De naam van het in te lezen gegevensbestand, URL, wordt verkregen met de volgende code:
// de bestandsnaam van de belastingtabel ophalen
String nomFichier=getParameter("data");
// fout?
if(nomFichier==null){
// foutmelding
txtStatus.setText("Le paramètre data de l'applet n'a pas été initialisé");
// de optie Initialiseren wordt geblokkeerd
mnuInitialiser.setEnabled(false);
// einde
return;
}//if
// de URL van de gegevens wordt vastgelegd
urlDATA=getCodeBase()+"/"+nomFichier;
Laten we niet vergeten dat de bestandsnaam "impots.txt" is doorgegeven aan de parameter data van de applet:
De bovenstaande code begint dus met het ophalen van de waarde van de parameter data, waarbij rekening wordt gehouden met een eventuele fout. Als de parameter URL van het document HTML waarin de applet is opgenomen, http://localhost:81/JApplets/impots/appletImpots.htm is, dan is de URL van het bestand impots.txt http://localhost:81/JApplets/impots/impots.txt. We moeten de naam van dit URL samenstellen. De methode getCodeBase() van de applet geeft de URL van de map waaruit het document HTML met de applet is opgehaald, dus in ons voorbeeld http://localhost:81/JApplets/impots. Met de volgende instructie kunnen we dus de URL van het gegevensbestand samenstellen:
In de methode lireFichier() wordt de inhoud van URL en urlData gelezen, waarbij de invoerstroom wordt aangemaakt waarmee de gegevens kunnen worden ingelezen:
// bestand openen voor lezen
BufferedReader IN=new BufferedReader(new InputStreamReader(new URL(urlDATA).openStream()));
Vanaf dat moment is het niet meer te onderscheiden of de gegevens uit een extern of een lokaal bestand afkomstig zijn. Hier volgt een voorbeeld van de uitvoering van de applet:

5.8. Conclusie
In dit hoofdstuk is
- een inleiding gegeven tot het bouwen van grafische interfaces met JBuilder
- de meest gangbare Swing-componenten
- het bouwen van applets
We onthouden dat
- de door JBuilder gegenereerde code met de hand kan worden geschreven. Zodra deze code op de een of andere manier is verkregen, volstaat een eenvoudige JDK om deze uit te voeren en is JBuilder dan niet langer onmisbaar.
- het gebruik van een tool zoals JBuilder kan aanzienlijke productiviteitswinst opleveren:
- hoewel het mogelijk is om de door JBuilder gegenereerde code met de hand te schrijven, kan dit veel tijd kosten en heeft het weinig zin, aangezien de logica van de applicatie doorgaans elders ligt.
- De gegenereerde code kan leerzaam zijn. Het lezen en bestuderen ervan is een goede manier om bepaalde methoden en eigenschappen te ontdekken van componenten die men voor het eerst gebruikt.
- JBuilder is platformonafhankelijk. Je behoudt dus je opgedane kennis wanneer je van het ene platform naar het andere overschakelt. Het kunnen schrijven van programma’s die zowel onder Windows als onder Linux draaien, is natuurlijk een zeer belangrijke productiviteitsfactor. Maar dit is te danken aan Java zelf en niet aan JBuilder.
5.9. JBuilder onder Linux
Alle voorgaande voorbeelden zijn getest onder Windows 98. Je kunt je afvragen of de geschreven programma’s zonder aanpassingen draaien onder Linux. Mits de betreffende Linux-machine beschikt over de klassen die door de verschillende programma’s worden gebruikt, is dat het geval. Als je bijvoorbeeld JBuilder onder Linux hebt geïnstalleerd, staan de benodigde klassen al op je machine. Hieronder ziet u bijvoorbeeld het resultaat van het uitvoeren van een van onze programma’s op de component JList met JBuilder 4 onder Linux:
Hieronder beschrijven we de installatie van JBuilder 4 Foundation op een Linux-computer. De installatie op een Win9x-computer verloopt probleemloos en verloopt op dezelfde manier als het proces dat hierna wordt beschreven. De installatie van latere versies is waarschijnlijk anders, maar dit document kan niettemin enkele nuttige informatie bevatten.
JBuilder is beschikbaar op de website van Inprise via de URL http://www.inprise.com/jbuilder

Op deze pagina staan onder andere links voor Windows en Linux. We beschrijven nu de installatie van JBuilder op een Linux-computer met de grafische interface KDE.
Als je de link ‘Jbuilder 4 for Linux’ volgt, verschijnt er een formulier. Vul dit in en je krijgt uiteindelijk twee bestanden:
jb4docs_fr.tar.gz: de documentatie en voorbeelden van Jbuilder4
jb4fndlinux_fr.tar.gz: JBuilder 4 Foundation. Dit is een beperkte versie van de commerciële JBuilder 4, maar volstaat voor educatieve doeleinden.
U ontvangt per e-mail een activeringscode voor de software. Hiermee kunt u JBuilder 4 gebruiken en deze code wordt bij het eerste gebruik gevraagd. Mocht u deze code kwijtraken, dan kunt u teruggaan naar de bovenstaande URL en de link "get your activation key" volgen. We gaan er vervolgens vanuit dat u root bent en dat u zich in de map bevindt met de twee bovengenoemde bestanden tar.gz. Pak de twee bestanden uit:
[ls -l]
drwxr-xr-x 3 nobody nobody 4096 oct 10 2000 docs
drwxr-xr-x 3 nobody nobody 4096 déc 5 13:00 foundation
[ls -l foundation]
-rw-r--r-- 1 nobody nobody 1128 déc 5 13:00 deploy.txt
-rwxr-xr-x 1 nobody nobody 69035365 déc 5 13:00 fnd_linux_install.bin
drwxr-xr-x 2 nobody nobody 4096 déc 5 13:00 images
-rw-r--r-- 1 nobody nobody 15114 déc 5 13:00 index.html
-rw-r--r-- 1 nobody nobody 23779 déc 5 13:00 license.txt
-rw-r--r-- 1 nobody nobody 75739 déc 5 13:00 release_notes.html
-rw-r--r-- 1 nobody nobody 31902 déc 5 13:00 whatsnew.html
[ls -l docs]
-rw-r--r-- 1 nobody nobody 1128 oct 10 2000 deploy.txt
-rwxr-xr-x 1 nobody nobody 40497874 oct 10 2000 doc_install.bin
drwxr-xr-x 2 nobody nobody 4096 oct 10 2000 images
-rw-r--r-- 1 nobody nobody 9210 oct 10 2000 index.html
-rw-r--r-- 1 nobody nobody 23779 oct 10 2000 license.txt
-rw-r--r-- 1 nobody nobody 75739 oct 10 2000 release_notes.html
-rw-r--r-- 1 nobody nobody 31902 oct 10 2000 whatsnew.html
In de twee gegenereerde mappen is het bestand .bin het installatiebestand. Open bovendien met een browser het bestand index.html in elk van de mappen. Daarin staat de procedure voor het installeren van beide producten. Laten we beginnen met het installeren van JBuilder Foundation:
Het eerste installatiescherm verschijnt. Er volgen nog vele andere:

Bevestig. Er volgt een scherm met uitleg:

Voer [suivant] uit.

Accepteer de licentieovereenkomst en voer [suivant] uit.

Accepteer de voorgestelde locatie voor JBuilder (noteer deze, je hebt hem later nodig) en voer [suivant] uit. De installatie verloopt snel.

We zijn klaar voor een eerste test. Start in KDE de bestandsbeheerder om naar de map met de uitvoerbare bestanden van Jbuilder te gaan: /opt/jbuilder4/bin (als je Jbuilder in /opt/jbuilder4 hebt geïnstalleerd):

Klik op het pictogram jbuilder hierboven. Aangezien dit de eerste keer is dat u JBuilder gebruikt, moet u uw activeringscode invoeren:

Vul de velden Nom en Société in. Klik op [Ajouter] om uw activeringscode in te voeren. Ter herinnering: deze code is u per e-mail toegestuurd. Mocht u deze kwijt zijn, dan kunt u deze terugvinden op de URL waar u JBuilder 4 hebt gedownload (zie het begin van de installatie). Zodra uw activeringscode is geaccepteerd, worden de licentievoorwaarden nogmaals weergegeven:

Door OK in te voeren, keert u terug naar het eerder getoonde venster voor het invoeren van gegevens:

Voer OK in om deze fase af te ronden, die alleen bij de eerste keer uitvoeren plaatsvindt. Vervolgens verschijnt de ontwikkelomgeving van JBuilder:

Sluit JBuilder af om nu de documentatie te installeren. Hiermee worden een aantal bestanden geïnstalleerd die worden gebruikt in de helpfunctie van JBuilder, die op dit moment nog onvolledig is. Ga terug naar de map waarin u de JBuilder-bestanden tar.gz hebt uitgepakt. Het installatieprogramma bevindt zich in de map docs. Ga daarheen:
[cd docs]
[ls -l]
-rw-r--r-- 1 nobody nobody 1128 oct 10 2000 deploy.txt
-rwxr-xr-x 1 nobody nobody 40497874 oct 10 2000 doc_install.bin
drwxr-xr-x 2 nobody nobody 4096 oct 10 2000 images
-rw-r--r-- 1 nobody nobody 9210 oct 10 2000 index.html
-rw-r--r-- 1 nobody nobody 23779 oct 10 2000 license.txt
-rw-r--r-- 1 nobody nobody 75739 oct 10 2000 release_notes.html
-rw-r--r-- 1 nobody nobody 31902 oct 10 2000 whatsnew.html
Het installatiebestand is doc_install.bin, maar u kunt het niet direct starten. Als u dat wel doet, mislukt de installatie zonder dat u begrijpt waarom. Lees het bestand index.html met een browser voor een gedetailleerde beschrijving van de installatieprocedure. Het installatieprogramma heeft een Java Virtual Machine nodig, namelijk een programma met de naam java, en dit programma moet zich in de map PATH op uw computer bevinden. Ter herinnering: PATH is een Unix-variabele waarvan de waarde in de vorm rep1:rep2:...:repn de mappen repi aangeeft die moeten worden doorzocht bij het zoeken naar een uitvoerbaar bestand. Hier vraagt het installatieprogramma om het uitvoeren van een programma met de naam java. U kunt meerdere versies van dit programma hebben, afhankelijk van het aantal virtuele Java-machines dat u hier en daar hebt geïnstalleerd. Logischerwijs gebruiken we de versie die door Jbuilder4 wordt meegeleverd en die zich bevindt in /opt/jbuilder4/jdk1.3/bin. Om deze map in de variabele PATH op te nemen:
[echo $PATH]
/usr/local/sbin:/usr/sbin:/sbin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin
[export PATH=/opt/jbuilder4/jdk1.3/bin/:$PATH]
[echo $PATH]
/opt/jbuilder4/jdk1.3/bin/:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin
We kunnen nu de installatie van de documentatie starten:
Er wordt nu een grafische installatie uitgevoerd:

Deze lijkt sterk op die van JBuilder Foundation. We zullen er daarom niet in detail op ingaan. Er is één scherm dat u niet mag missen:

Het installatieprogramma zou normaal gesproken zelf moeten vinden waar u JBuilder Foundation hebt geïnstalleerd. Wijzig de voorgestelde instellingen dus niet, tenzij deze natuurlijk onjuist zijn.
Zodra de documentatie is geïnstalleerd, zijn we klaar voor een nieuwe test van JBuilder. Start de toepassing zoals hierboven is getoond. Zodra JBuilder is opgestart, kiest u de optie Help/Helponderwerp. Klik in het linkervenster op de link Tutoriels:

JBuilder wordt geleverd met een reeks tutorials waarmee u aan de slag kunt gaan met Java-programmeren. Hieronder hebben we de tutorial „Een applicatie bouwen“ gevolgd.

Ga in JBuilder naar Bestand/Nieuw project. Een wizard toont u drie schermen:

We gaan een eenvoudig venster maken met de titel "Hallo allemaal". We noemen dit project coucou. Het voorbeeld is uitgevoerd door root. JBuilder stelt vervolgens voor om alle projecten samen te voegen in een map jbproject binnen de verbindingsmap van root. Het project coucou wordt geplaatst in de map coucou (veld ‘Naam van de projectmap’) van jbproject. Maak [suivant] aan.

Dit tweede scherm geeft een overzicht van de verschillende paden in uw project. U hoeft hier niets te wijzigen. Voer [suivant] uit.

Op het derde scherm wordt u gevraagd uw project aan te passen. Vul de gegevens in en voer [Terminer] uit.
Voer nu Fichier/Nouveau uit:

Kies Application en voer OK uit. Een nieuwe wizard toont u twee schermen:

Het veld paquet bevat de naam van het project. In het veld ‘klasse’ moet u nom invoeren, de naam die aan de hoofdklasse van het project wordt toegekend. Neem de bovenstaande naam en voer [suivant] in:

Onze applicatie bevat een tweede Java-klasse voor het applicatievenster. Geef deze klasse een naam. Het veld Titre is de titel die u aan dit venster wilt geven. Het kader options biedt u opties voor uw venster. Selecteer ze allemaal en voer [Terminer] in. U keert dan terug naar de JBuilder-omgeving, die is aangevuld met de informatie die u voor uw project hebt opgegeven:

In het venster linksboven (1) ziet u de lijst met bestanden waaruit uw project bestaat. Daarin staan onder andere de twee klassen .java waaraan we zojuist een naam hebben gegeven. In het venster rechts (2) ziet u de Java-code van de klasse coucouCadre. In het venster linksonder ziet u de structuur (klassen, methoden, attributen) van uw project. Het is klaar om te worden uitgevoerd. Klik op knop 4 hierboven, of kies Uitvoeren/Project uitvoeren, of selecteer F9. U zou het volgende venster moeten zien:

Als u op de optie Aide klikt, zou u de informatie moeten terugvinden die u aan de aanmaakwizards hebt verstrekt. We gaan hier niet verder op in. Het is nu tijd om u in de tutorials te verdiepen.
Voordat we afsluiten, laten we even zien dat u niet JBuilder en zijn grafische interface hoeft te gebruiken, maar het JDK dat het programma heeft meegebracht en in /opt/jbuilder4/jdk1.3 heeft geplaatst. Compileer het volgende bestand essai1.java:
import java.io.*;
public class essai1{
public static void main(String args[]){
System.out.println("coucou");
System.exit(0);
}
}
Laten we het compileren en uitvoeren met de JDK van JBuilder:






