5. Interfejsy graficzne
W tym miejscu zamierzamy pokazać, jak tworzyć interfejsy graficzne za pomocą JAVA. Najpierw przyjrzymy się, jakie klasy bazowe pozwalają nam zbudować interfejs graficzny. Na początku nie będziemy korzystać z żadnego narzędzia do automatycznego generowania. Następnie wykorzystamy JBuilder, narzędzie programistyczne firmy Borland/Inprise ułatwiające tworzenie aplikacji Java, a w szczególności budowę interfejsów graficznych.
5.1. Podstawy interfejsów graficznych
5.1.1. Proste okno
Rozważmy następujący kod:
// zaimportowane klasy
import javax.swing.*;
import java.awt.*;
// klasa formularza
public class form1 extends JFrame {
// konstruktor
public form1() {
// tytuł okna
this.setTitle("Mon premier formulaire");
// wymiary okna
this.setSize(new Dimension(300,100));
}//konstruktor
// funkcja testowa
public static void main(String[] args) {
// wyświetla się formularz
new form1().setVisible(true);
}
}//klasa
Wykonanie powyższego kodu powoduje wyświetlenie następującego okna:

Interfejs graficzny zazwyczaj dziedziczy po klasie bazowej JFrame:
public class form1 extends JFrame {
Klasa bazowa JFrame definiuje podstawowe okno z przyciskami zamykania, powiększania/zmniejszania, regulacją rozmiaru itp. oraz obsługuje zdarzenia związane z tymi obiektami graficznymi. W tym przypadku specjalizujemy klasę bazową, ustalając jej tytuł oraz szerokość (300 pikseli) i wysokość (100 pikseli). Odbywa się to w jej konstruktorze:
// konstruktor
public form1() {
// tytuł okna
this.setTitle("Mon premier formulaire");
// wymiary okna
this.setSize(new Dimension(300,100));
}//konstruktor
Tytuł okna jest ustalany przez metodę setTitle, a jego wymiary przez metodę setSize. Metoda ta przyjmuje jako parametr obiekt Dimension(largeur,hauteur), gdzie largeur i hauteur to szerokość i wysokość okna wyrażone w pikselach.
Metoda main uruchamia aplikację graficzną w następujący sposób:
new form1().setVisible(true);
Następnie tworzony jest formularz typu form1 (new form1()) i wyświetlany (setVisible(true)), po czym aplikacja zaczyna nasłuchiwać zdarzeń występujących w formularzu (kliknięcia, ruchy myszy, ...) i uruchamia te, które obsługuje formularz. W tym przypadku nasz formularz nie obsługuje żadnych innych zdarzeń poza tymi, które obsługuje klasa bazowa JFrame (kliknięcia przycisków zamykania, powiększania/zmniejszania, zmiana rozmiaru okna, przesuwanie okna itp.).
Podczas testowania tego programu, uruchamiając go z okna DOS za pomocą polecenia:
w celu uruchomienia pliku form1.class, można zauważyć, że po zamknięciu wyświetlonego okna nie następuje „przejęcie kontroli” w oknie DOS, tak jakby program nie został zakończony. Tak właśnie jest. Program działa w następujący sposób:
- na początku uruchamiany jest pierwszy wątek wykonawczy w celu wykonania metody main
- gdy ta tworzy formularz i wyświetla go, tworzony jest drugi wątek, który zajmuje się konkretnie obsługą zdarzeń związanych z formularzem
- po tym utworzeniu, w naszym przykładzie, wątek metody main kończy działanie i pozostaje tylko wątek wykonawczy interfejsu graficznego.
- Po zamknięciu okna znika ono, ale nie przerywa działania wątku, w którym było uruchomione
- na razie musimy zatrzymać ten wątek, naciskając Ctrl-C w oknie DOS, z którego uruchomiono program.
Sprawdźmy, czy istnieją dwa oddzielne wątki: jeden, w którym wykonywana jest metoda main, a drugi, w którym działa okno graficzne:
// importowane klasy
import javax.swing.*;
import java.awt.*;
import java.io.*;
// klasa formularza
public class form1 extends JFrame {
// konstruktor
public form1() {
// tytuł okna
this.setTitle("Mon premier formulaire");
// wymiary okna
this.setSize(new Dimension(300,100));
}//konstruktor
// funkcja testowa
public static void main(String[] args) {
// śledzenie
System.out.println("Début du thread main");
// wyświetla się formularz
new form1().setVisible(true);
// śledzenie
System.out.println("Fin du thread main");
}//główna
}//klasa
Wynik wykonania jest następujący:

Można zauważyć, że wątek main został zakończony, podczas gdy okno jest nadal wyświetlane. Zamknięcie okna nie powoduje zakończenia wątku, w którym było ono uruchomione. Aby zatrzymać ten wątek, należy ponownie nacisnąć klawisze Ctrl-C w oknie DOS.
Na zakończenie tego przykładu należy zwrócić uwagę na zaimportowane pakiety:
- javax.swing dla klasy JFrame
- java.awt dla klasy Dimension
5.1.2. Obsługa zdarzenia
W poprzednim przykładzie musielibyśmy samodzielnie obsłużyć zamknięcie okna, aby w momencie jego zamknięcia zatrzymać działanie aplikacji, co na razie nie ma miejsca. W tym celu musimy utworzyć obiekt, który „nasłuchuje” zdarzeń występujących w oknie i wykrywa zdarzenie „zamknięcie okna”. Obiekt ten nazywamy „listenerem” lub menedżerem zdarzeń. Istnieją różne typy menedżerów dla różnych zdarzeń, które mogą wystąpić w komponentach interfejsu graficznego. W przypadku komponentu JFrame listener nosi nazwę WindowListener i jest interfejsem definiującym następujące metody (patrz dokumentacja Java)
Podsumowanie metod | ||
void | windowActivated(WindowEvent e) Okno staje się oknem aktywnym | |
void | windowClosed(WindowEvent e) Okno zostało zamknięte | |
void | windowClosing(WindowEvent e) Użytkownik lub program zażądał zamknięcia okna | |
void | windowDeactivated(WindowEvent e) Okno nie jest już oknem aktywnym | |
void | windowDeiconified(WindowEvent e) Okno przechodzi ze stanu zminimalizowanego do stanu normalnego | |
void | windowIconified(WindowEvent e) Okno przechodzi ze stanu normalnego do stanu zminimalizowanego | |
void | windowOpened(WindowEvent e) Okno staje się widoczne po raz pierwszy | |
Istnieje zatem siedem zdarzeń, które można obsłużyć. Wszystkie procedury obsługi otrzymują jako parametr obiekt typu WindowEvent, który na razie pomijamy. Zdarzeniem, które nas tutaj interesuje, jest zamknięcie okna – zdarzenie to powinno zostać obsłużone przez metodę windowClosing. Aby obsłużyć to zdarzenie, można utworzyć obiekt Windowlistener za pomocą klasy anonimowej w następujący sposób:
// utworzenie menedżera zdarzeń
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){}
};//definicja win
Nasz menedżer zdarzeń implementujący interfejs WindowListener musi zdefiniować wszystkie siedem metod tego interfejsu. Ponieważ chcemy obsługiwać wyłącznie zamknięcie okna, definiujemy kod tylko dla metody windowClosing. Gdy wystąpią inne zdarzenia, otrzymamy o nich powiadomienie, ale nie podejmiemy żadnych działań. Co zrobimy, gdy otrzymamy powiadomienie, że okno jest zamykane (windowClosing)? Zakończymy działanie aplikacji:
public void windowClosing(WindowEvent e){System.exit(0);}
Mamy tu obiekt zdolny do obsługi zdarzeń okna w uogólnieniu. Jak powiązać go z konkretnym oknem? Klasa JFrame posiada metodę addWindowListener(WindowListener win), która pozwala powiązać menedżera zdarzeń „okna” z danym oknem. W związku z tym w konstruktorze okna napiszemy:
// utworzenie menedżera zdarzeń
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){}
};//definicja w systemie Windows
// ten menedżer zdarzeń będzie obsługiwał zdarzenia bieżącego okna
this.addWindowListener(win);
Pełny program przedstawia się następująco:
// zaimportowane klasy
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
// klasa formularza
public class form2 extends JFrame {
// konstruktor
public form2() {
// tytuł okna
this.setTitle("Mon premier formulaire");
// wymiary okna
this.setSize(new Dimension(300,100));
// utworzenie menedżera zdarzeń
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){}
};//definicja systemu Windows
// ten menedżer zdarzeń będzie obsługiwał zdarzenia bieżącego okna
this.addWindowListener(win);
}//konstruktor
// funkcja testowa
public static void main(String[] args) {
// wyświetla się formularz
new form2().setVisible(true);
}//main
}//klasa
Pakiet java.awt.event zawiera interfejs WindowListener. Po uruchomieniu tego programu i zamknięciu wyświetlonego okna w oknie DOS, w którym program został uruchomiony, widoczne jest zakończenie jego działania, czego wcześniej nie było.
W naszym programie tworzenie obiektu odpowiedzialnego za obsługę zdarzeń okna jest nieco uciążliwe, ponieważ musimy definiować metody nawet dla zdarzeń, których nie chcemy obsługiwać. W takim przypadku zamiast korzystać z interfejsu WindowListener można użyć klasy WindowAdapter. Klasa ta implementuje interfejs WindowListener, zawierający siedem pustych metod. Poprzez utworzenie klasy pochodnej od klasy WindowAdapter i przedefiniowanie wyłącznie tych metod, które nas interesują, uzyskujemy ten sam wynik, co w przypadku interfejsu WindowListener, ale bez konieczności definiowania metod, które nas nie interesują. Sekwencja
- definicja obsługi zdarzeń
- powiązanie obsługi z oknem
można w naszym przykładzie zrealizować w następujący sposób:
// tworzenie menedżera zdarzeń
WindowAdapter win=new WindowAdapter(){
public void windowClosing(WindowEvent e){System.exit(0);}
};//definicja okna
// ten menedżer zdarzeń będzie obsługiwał zdarzenia bieżącego okna
this.addWindowListener(win);
W tym miejscu wykorzystujemy klasę anonimową, która dziedziczy po klasie WindowAdapter i redefiniuje jej metodę windowClosing. Program wygląda wówczas następująco:
// zaimportowane klasy
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
// klasa formularza
public class form2 extends JFrame {
// konstruktor
public form2() {
// tytuł okna
this.setTitle("Mon premier formulaire");
// wymiary okna
this.setSize(new Dimension(300,100));
// utworzenie obsługi zdarzeń
WindowAdapter win=new WindowAdapter(){
public void windowClosing(WindowEvent e){System.exit(0);}
};//definicja systemu Windows
// ten menedżer zdarzeń będzie obsługiwał zdarzenia bieżącego okna
this.addWindowListener(win); }//konstruktor
// funkcja testowa
public static void main(String[] args) {
// wyświetla się formularz
new form2().setVisible(true);
}//main
}//klasa
Daje on takie same wyniki jak poprzedni program, ale jest prostszy w pisaniu.
5.1.3. Formularz z przyciskiem
Dodajmy teraz przycisk do naszego okna:
// zaimportowane klasy
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
// klasa formularza
public class form3 extends JFrame {
// przycisk
JButton btnTest=null;
Container conteneur=null;
// konstruktor
public form3() {
// tytuł okna
this.setTitle("Formulaire avec bouton");
// wymiary okna
this.setSize(new Dimension(300,100));
// tworzenie obsługi zdarzeń
WindowAdapter win=new WindowAdapter(){
public void windowClosing(WindowEvent e){System.exit(0);}
};//definicja systemu Windows
// ten menedżer zdarzeń będzie obsługiwał zdarzenia bieżącego okna
this.addWindowListener(win);
// pobieramy kontener okna
conteneur=this.getContentPane();
// wybieramy menedżera formatowania komponentów w tym kontenerze
conteneur.setLayout(new FlowLayout());
// tworzymy przycisk
btnTest=new JButton();
// ustalamy jego etykietę
btnTest.setText("Test");
// dodajemy przycisk do kontenera
conteneur.add(btnTest);
}//konstruktor
// funkcja testowa
public static void main(String[] args) {
// wyświetla się formularz
new form3().setVisible(true);
}//main
}//klasa
Okno JFrame posiada kontener, w którym można umieszczać elementy graficzne (przyciski, pola wyboru, listy rozwijane itp.). Kontener ten jest dostępny za pośrednictwem metody getContentPane klasy JFrame:
Container conteneur=null;
..........
// pobieranie kontenera okna
conteneur=this.getContentPane();
Każdy komponent jest umieszczany w kontenerze za pomocą metody add klasy Container. Aby zatem umieścić komponent C w poprzednim obiekcie conteneur, należy napisać:
Gdzie ten komponent jest umieszczany w kontenerze? Istnieje wiele menedżerów rozmieszczenia komponentów o nazwie XXXLayout, przy czym XXX jest na przykład równy Border, Flow, ... Każdy menedżer układu ma swoje specyficzne cechy. Na przykład menedżer FlowLayout rozmieszcza komponenty w wierszach, zaczynając od górnej części formularza. Po wypełnieniu wiersza komponenty są umieszczane w następnym wierszu. Aby powiązać menedżera układu z oknem JFrame, należy użyć metody setLayout klasy JFrame w następującej postaci:
W naszym przykładzie, aby powiązać menedżera typu FlowLayout z oknem, napisaliśmy:
// wybieramy menedżera formatowania komponentów w tym kontenerze
conteneur.setLayout(new FlowLayout());
Można zrezygnować z użycia menedżera układu i wpisać:
W takim przypadku należy podać dokładne współrzędne komponentu w kontenerze w postaci (x, y, szerokość, wysokość), gdzie (x, y) to współrzędne lewego górnego rogu komponentu w kontenerze. To właśnie tej metody będziemy najczęściej używać w dalszej części.
Wiemy już, w jaki sposób komponenty są umieszczane w kontenerze (add) i gdzie (setLayout). Pozostaje nam jeszcze poznać
komponenty, które można umieścić w kontenerze. W tym przypadku umieszczamy przycisk modelowany przez klasę javax.swing.JButton:
JButton btnTest=null;
..........
// tworzymy przycisk
btnTest=new JButton();
// ustalamy jego etykietę
btnTest.setText("Test");
// dodajemy przycisk do kontenera
conteneur.add(btnTest);
Podczas testowania tego programu pojawia się następujące okno:

Jeśli zmienimy rozmiar powyższego formularza, automatycznie uruchamia się menedżer układu kontenera, który ponownie rozmieszcza komponenty:

To właśnie główna zaleta menedżerów układu: utrzymywanie spójnego rozmieszczenia komponentów przy zmianach rozmiaru kontenera. Skorzystajmy z menedżera układu null, aby zobaczyć różnicę. Przycisk jest teraz umieszczany w kontenerze za pomocą następujących instrukcji:
// wybieramy menedżera formatowania komponentów w tym kontenerze
conteneur.setLayout(null);
// tworzymy przycisk
btnTest=new JButton();
// ustala się jego etykietę
btnTest.setText("Test");
// ustala się jego położenie i wymiary
btnTest.setBounds(10,20,100,20);
// dodajemy przycisk do kontenera
conteneur.add(btnTest);
W tym miejscu wyraźnie umieszczamy przycisk w punkcie (10,20) formularza i ustalamy jego wymiary na 100 pikseli szerokości i 20 pikseli wysokości. Nowe okno wygląda następująco:

Jeśli zmienimy rozmiar okna, przycisk pozostanie w tym samym miejscu.

Po kliknięciu przycisku Test nic się nie dzieje. Nie przypisaliśmy bowiem jeszcze do przycisku żadnego obsługi zdarzeń. Aby sprawdzić, jakie typy procedur obsługi zdarzeń są dostępne dla danego komponentu, można przeszukać definicję jego klasy pod kątem metod addXXXListener, które umożliwiają przypisanie do komponentu procedury obsługi zdarzeń. Klasa javax.swing.JButton wywodzi się z klasy javax.swing.AbstractButton, w której znajdują się następujące metody:
Podsumowanie metod | ||
void | addActionListener(ActionListener l) | |
void | addChangeListener(ChangeListener l) | |
void | addItemListener(ItemListener l) | |
W tym przypadku należy zapoznać się z dokumentacją, aby dowiedzieć się, który obsługujący zdarzenia zarządza kliknięciem przycisku. Jest to interfejs ActionListener. Interfejs ten definiuje tylko jedną metodę:
Podsumowanie metod | ||
void | actionPerformed(ActionEvent e) | |
Metoda ta przyjmuje parametr ActionEvent, który na razie zignorujemy. Aby obsłużyć kliknięcie przycisku btntest w naszym programie, najpierw przypisujemy do niego obsługę zdarzeń:
btnTest.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt){
btnTest_clic(evt);
}
}//klasa anonimowa
);//– menedżer zdarzeń
W tym przypadku metoda actionPerformed odwołuje się do metody btnTest_clic, którą definiujemy w następujący sposób:
public void btnTest_clic(ActionEvent evt){
// monitorowanie konsoli
System.out.println("clic sur bouton");
}//btnTest_click
Za każdym razem, gdy użytkownik kliknie przycisk Test, na konsoli wyświetlany jest komunikat. Pokazuje to poniższe wykonanie:

Pełny kod programu wygląda następująco:
// klasy importowane
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;
// klasa formularza
public class form4 extends JFrame {
// przycisk
JButton btnTest=null;
Container conteneur=null;
// konstruktor
public form4() {
// tytuł okna
this.setTitle("Formulaire avec bouton");
// wymiary okna
this.setSize(new Dimension(300,100));
// tworzenie obsługi zdarzeń
WindowAdapter win=new WindowAdapter(){
public void windowClosing(WindowEvent e){System.exit(0);}
};//definicja systemu Windows
// ten menedżer zdarzeń będzie obsługiwał zdarzenia bieżącego okna
this.addWindowListener(win);
// pobieramy kontener okna
conteneur=this.getContentPane();
// wybieramy menedżera formatowania komponentów w tym kontenerze
conteneur.setLayout(null);
// tworzymy przycisk
btnTest=new JButton();
// ustalamy jego etykietę
btnTest.setText("Test");
// ustala się jego położenie i wymiary
btnTest.setBounds(10,20,100,20);
// przypisuje się do niego menedżera zdarzeń
btnTest.addActionListener(new ActionListener()
{
public void actionPerformed(ActionEvent evt){
btnTest_clic(evt);
}
}//klasa anonimowa
);//– obsługa zdarzeń
// dodajemy przycisk do kontenera
conteneur.add(btnTest);
}//konstruktor
public void btnTest_clic(ActionEvent evt){
// śledzenie konsoli
System.out.println("clic sur bouton");
}//btnTest_click
// funkcja testowa
public static void main(String[] args) {
// wyświetlanie formularza
new form4().setVisible(true);
}//główna
}//klasa
5.1.4. Menedżery zdarzeń
Głównymi komponentami Swing, które przedstawimy, są okna (JFrame), przyciski (JButton), pola wyboru (JCheckBox), przyciski opcji (JButtonRadio), listy rozwijane (JComboBox), listy (JList), suwaki (JScrollBar), etykiety (JLabel), pola tekstowe jednowierszowe (JTextField) lub wielowierszowe (JTextArea), menu (JMenuBar), elementy menu (JMenuItem).
Poniższe tabele zawierają listę niektórych menedżerów zdarzeń oraz zdarzeń, z którymi są one powiązane.
Obsługa | Komponent(y) | Metoda rejestracji | Zdarzenie |
ActionListener | JButton, JCheckbox, JButtonRadio, JMenuItem | public void addActionListener(ActionListener) | kliknięcie przycisku, pola wyboru, przycisku opcji, elementu menu |
JTextField | |||
ItemListener | JComboBox, JList | public void addItemListener(ItemListener) | Wybrany element uległ zmianie |
InputMethodListener | JTextField, JTextArea | public void addMethodInputListener(InputMethodListener) | tekst w polu wprowadzania danych uległ zmianie lub kursor wprowadzania danych zmienił położenie |
CaretListener | JTextField, JTextArea | public void addcaretListener(CaretListener) | Kursor wprowadzania danych zmienił pozycję |
AdjustmentListener | JScrollBar | public void addAdjustmentListener(AdjustmentListener) | zmieniła się wartość regulatora |
MouseMotionListener | public void addMouseMotionListener(MouseMotionListener) | mysz się poruszyła | |
WindowListener | JFrame | public void addWindowlistener(WindowListener) | zdarzenie okna |
MouseListener | public void addMouselistener(MouseListener) | zdarzenia myszy (kliknięcie, wejście/wyjście z obszaru komponentu, naciśnięcie przycisku, zwolnienie przycisku) | |
FocusListener | public void addFocuslistener(FocusListener) | zdarzenie focus (uzyskane, utracone) | |
KeyListener | public void addKeylistener(KeyListener) | zdarzenie klawiatury (naciśnięcie, przytrzymanie, zwolnienie klawisza) |
Komponent | Metoda rejestrowania procedur obsługi zdarzeń |
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 | jako kontener |
JScrollPane | jako kontener |
JScrollBar | public void addAdjustmentListener(AdjustmentListener) |
JTextComponent | public void addInputMethodListener(InputMethodListener) public void addCaretListener(CaretListener) |
JTextArea | comme JTextComponent |
JTextField | jak JTextComponent public void addActionListener(ActionListener) |
Wszystkie komponenty, z wyjątkiem tych typu TextXXX, będące pochodnymi klasy JComponent, posiadają również metody związane z tą klasą.
5.1.5. Metody obsługi zdarzeń
Poniższa tabela zawiera listę metod, które muszą być zaimplementowane przez poszczególne obsługujące zdarzenia.
Interfejs | Metody |
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. Klasy adapterowe
Jak widzieliśmy w przypadku interfejsu WindowListener, istnieją klasy o nazwie XXXAdapter, które implementują interfejsy XXXListener za pomocą pustych metod. Obsługa zdarzeń wywodząca się z klasy XXXAdapter może zatem implementować tylko część metod interfejsu XXXListener, a mianowicie te, których potrzebuje aplikacja.
Załóżmy, że chcemy obsługiwać kliknięcia myszą na komponencie Frame f1. Można by przypisać do niego obsługę zdarzeń w następujący sposób:
i napisać:
public class gestionnaireSouris implements MouseListener{
// piszemy 5 metod interfejsu MouseListener
// mouseClicked, ..., mouseReleased)
}// koniec klasy
Ponieważ chcemy obsługiwać wyłącznie kliknięcia myszą, lepiej jednak wpisać:
public class gestionnaireSouris extends MouseAdapter{
// piszemy tylko jedną metodę, tę, która obsługuje kliknięcia myszą
public void mouseClicked(MouseEvent evt){
…
}
}// koniec klasy
Poniższa tabela przedstawia klasy adapterów poszczególnych menedżerów zdarzeń:
Moduł obsługi zdarzeń | Adapter |
ComponentListener | ComponentAdapter |
ContainerListener | ContainerAdapter |
FocusListener | FocusAdapter |
KeyListener | KeyAdapter |
MouseListener | MouseAdapter |
MouseMotionListener | MouseMotionAdapter |
WindowListener | WindowAdapter |
5.1.7. Podsumowanie
Przedstawiliśmy właśnie podstawowe pojęcia związane z tworzeniem interfejsów graficznych w języku Java:
- tworzenie okna
- tworzenie komponentów
- przypisywanie komponentów do okna za pomocą menedżera układu
- przypisywanie menedżerów zdarzeń do komponentów
Teraz, zamiast tworzyć interfejsy graficzne „ręcznie”, tak jak to właśnie zrobiliśmy, skorzystamy z JBuilder, narzędzia do programowania w Javie firmy Borland/Inprise w wersji 4, oraz z komponentów biblioteki supérieure.Nous, obecnie zalecanej przez firmę Sun, twórcę języka Java.
5.2. Tworzenie interfejsu graficznego za pomocą JBuilder
5.2.1. Nasz pierwszy projekt w JBuilderze
Aby zapoznać się z programem JBuilder, stwórzmy bardzo prostą aplikację: puste okno.
- Uruchom JBuilder i wybierz opcję Plik/Nowy projekt. Pojawi się pierwsza strona kreatora:

- Wypełnij następujące pola:
Nazwa projektu | Początek spowoduje utworzenie pliku projektu début.jpr w folderze wskazanym w polu „Nazwa katalogu projektu” |
Ścieżka główna | należy podać katalog, w którym zostanie utworzony katalog projektu, który zamierzasz utworzyć. |
Nazwa katalogu projektu | podaj nazwę folderu, w którym zostaną umieszczone wszystkie pliki projektu. Folder ten zostanie utworzony w katalogu wskazanym w polu „Ścieżka główna” |
Pliki źródłowe (.java, .html itp.), pliki docelowe (.class itp.) oraz pliki kopii zapasowych mogą znajdować się w różnych katalogach. Jeśli pola te pozostaną puste, pliki te zostaną umieszczone w tym samym katalogu co projekt.
Wpisz [suivant]
- Ekran potwierdza wybory dokonane w poprzednim kroku

Wprowadź [suivant]
- Na nowym ekranie należy określić charakterystykę projektu:

Wybierz [terminer]
- Sprawdź, czy opcja Voir/projet jest zaznaczona. W lewym oknie powinna być widoczna struktura projektu.

- Teraz stwórzmy interfejs graficzny w tym projekcie. Wybierz opcję Fichier/Nouveau/Application:

W polu classe należy wpisać nazwę klasy, która zostanie utworzona. W tym przypadku użyto tej samej nazwy co nazwa projektu.
Wykonaj [suivant]
- Pojawi się następujący ekran:

Klasa | interfaceDébut Jest to nazwa klasy odpowiadającej oknu, które zostanie utworzone |
Tytuł | Jest to tekst, który pojawi się w pasku tytułu okna |
Należy zauważyć, że powyżej zadeklarowaliśmy, aby okno było wyśrodkowane na ekranie po uruchomieniu aplikacji.
Wpisz [Terminer]
- Właśnie teraz JBuilder okazuje się przydatny.
- Generuje on pliki źródłowe .java dla obu klas, których nazwy podaliśmy: klasy aplikacji oraz klasy interfejsu graficznego. Te dwa pliki pojawiają się w strukturze projektu w lewym oknie

- Aby uzyskać dostęp do wygenerowanego kodu dla obu klas, wystarczy dwukrotnie kliknąć odpowiedni plik .java. Do wygenerowanego kodu wrócimy później.
- Sprawdź, czy opcja Voir/Structure jest zaznaczona. Umożliwia ona wyświetlenie struktury aktualnie wybranej klasy (podwójne kliknięcie na plik .java). Oto na przykład struktura klasy début:

Tutaj dowiadujemy się:
-
o zaimportowanych bibliotekach (imports)
-
że istnieje konstruktor début()
-
że istnieje metoda statyczna main()
-
że istnieje atrybut packFrame
Jaki jest sens posiadania dostępu do struktury klasy?
-
uzyskujesz jej ogólny obraz. Jest to przydatne, jeśli twoja klasa jest złożona.
-
możesz uzyskać dostęp do kodu metody, klikając na nią w oknie struktury klasy. To również jest przydatne, jeśli twoja klasa ma setki wierszy. Nie musisz przeglądać wszystkich wierszy, aby znaleźć kod, którego szukasz.
Kod wygenerowany przez JBuilder jest już gotowy do użycia. Wybierz opcję „Uruchom/Uruchom projekt” lub „F9”, a pojawi się żądane okno:

Ponadto okno zamyka się poprawnie po kliknięciu przycisku zamykania. Właśnie stworzyliśmy nasz pierwszy interfejs graficzny. Możemy zapisać nasz projekt, wybierając opcję Plik/Zamknij projekty:

Po naciśnięciu Tous wszystkie projekty widoczne w powyższym oknie zostaną zaznaczone. OK spowoduje ich zamknięcie. Jeśli zechcemy przejść za pomocą Eksploratora Windows do folderu naszego projektu (tego, który został wskazany w kreatorze na początku konfiguracji projektu), znajdziemy w nim następujące pliki:

W naszym przykładzie poprosiliśmy, aby wszystkie pliki (źródłowe .java, docelowe .class, kopie zapasowe .jpr~) znajdowały się w tym samym folderze co plik projektu .jpr.
5.2.2. Pliki wygenerowane przez JBuilder dla interfejsu graficznego
Zajrzyjmy teraz z ciekawością, jakie pliki źródłowe .java wygenerował JBuilder. Ważne jest, aby umieć odczytać wygenerowany kod, ponieważ w większości przypadków musimy go uzupełniać o własny kod. Zacznijmy od załadowania naszego projektu: Plik/Otwórz projekt i wybierzmy projekt début.jpr. Znajdujemy tam wcześniej utworzony projekt.
5.2.2.1. Klasa główna
Przyjrzyjmy się klasie début.java, klikając dwukrotnie jej nazwę w oknie zawierającym listę plików projektu. Mamy następujący kod:
import javax.swing.UIManager;
import java.awt.*;
public class début {
boolean packFrame = false;
/**Tworzenie aplikacji*/
public début() {
interfaceDébut frame = new interfaceDébut();
//Sprawdzanie poprawności ramek o z góry określonych rozmiarach
//Kompresja ramek o preferowanych rozmiarach – np. na podstawie ich rozmieszczenia
if (packFrame) {
frame.pack();
}
else {
frame.validate();
}
//Wyśrodkowanie okna
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);
}
/**Metoda główna*/
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
}
catch(Exception e) {
e.printStackTrace();
}
new début();
}
}
Omówmy wygenerowany kod:
- funkcja main określa wygląd okna (setLookAndFeel) i tworzy instancję klasy début.
- Następnie uruchamiany jest konstruktor début(). Tworzy on instancję frame klasy okna (new interfaceDébut()). Instancja ta jest tworzona, ale nie jest wyświetlana.
- Następnie okno jest skalowane zgodnie z informacjami dostępnymi dla każdego z jego komponentów (frame.validate). W ten sposób rozpoczyna ono swoje samodzielne istnienie, wyświetlając się i reagując na działania użytkownika.
- Okno jest wyśrodkowane na ekranie, ponieważ tak określono podczas konfiguracji okna za pomocą kreatora.
Zobaczmy, jaki byłby efekt, gdybyśmy zredukowali kod début.java do absolutnego minimum, tak jak zrobiliśmy to na początku rozdziału. Utwórzmy nową klasę. Wybierz opcję Plik/Nowa klasa:

Nazwij nową klasę début2, a poprzednią zmień na [Terminer]. W projekcie pojawi się nowy plik:

Plik début2.java został zredukowany do najprostszej postaci:
Uzupełnijmy klasę w następujący sposób:
public class début2 {
// funkcja główna
public static void main(String args[]){
// tworzy okno
new interfaceDébut().show(); // lub new interfaceDébut.setVisible(true);
}//main
}//klasa début2
Funkcja main tworzy instancję okna interfaceDébut i wyświetla ją (show). Przed uruchomieniem naszego projektu należy zaznaczyć, że klasą zawierającą funkcję main, która ma zostać wykonana, jest teraz klasa début2. Kliknij prawym przyciskiem myszy na projekt début.jpr i wybierz opcję propriétés, a następnie zakładkę Exécution:
21

W tym miejscu wskazano, że klasą główną jest début (1). Naciśnij przycisk (2), aby wybrać inną klasę główną:

Wybierz début2 i wprowadź [OK].

Wprowadź [OK], aby zatwierdzić ten wybór, a następnie uruchom projekt, wybierając opcję Uruchom/Uruchom projekt lub wprowadzając F9. Pojawi się to samo okno, co w przypadku klasy début, z tą różnicą, że nie jest ono wyśrodkowane, ponieważ w tym przypadku nie zadano takiego żądania. W dalszej części nie będziemy już przedstawiać głównej klasy wygenerowanej przez JBuilder, ponieważ zawsze wykonuje ona tę samą czynność: tworzy okno. Od tej pory skupimy się na klasie tego okna.
5.2.2.2. Klasa okna
Przyjrzyjmy się teraz kodowi, który został wygenerowany dla klasy interfaceDébut:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class interfaceDébut extends JFrame {
JPanel contentPane;
BorderLayout borderLayout1 = new BorderLayout();
/**Utwórz ramkę*/
public interfaceDébut() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Inicjalizacja komponentu*/
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");
}
/**Zastąpiono, dzięki czemu możemy zakończyć działanie po zamknięciu okna*/
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
}
5.2.2.2.1. Zaimportowane biblioteki
Są to biblioteki java.awt, java.awt.event oraz javax.swing. Dwie pierwsze były jedynymi dostępnymi bibliotekami do tworzenia interfejsów graficznych w pierwszych wersjach Javy. Biblioteka javax.swing jest nowsza. W tym przypadku jest ona niezbędna dla okna typu JFrame, które jest tutaj wykorzystywane.
5.2.2.2.2. Atrybuty
JPanel to typ kontenera, w którym można umieszczać komponenty. BorderLayout jest jednym z dostępnych typów menedżerów formatowania służących do umieszczania komponentów w kontenerze. We wszystkich naszych przykładach nie będziemy korzystać z menedżera formatowania i sami umieścimy komponenty w określonym miejscu kontenera. W tym celu użyjemy menedżera formatowania null.
5.2.2.2.3. Konstruktor okna
/**Utworzenie ramki*/
public interfaceDébut() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Zainicjowanie komponentu*/
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");
}
- Konstruktor najpierw informuje, że będzie obsługiwał zdarzenia w oknie (enableEvents), a następnie wywołuje metodę jbInit.
- Pobierany jest kontener (JPanel) okna (JFrame) (getContentPane)
- Ustalono menedżera formatowania (setLayout)
- Rozmiar okna został ustalony (setSize)
- Ustalono tytuł okna (setTitle)
5.2.2.2.4. Menedżer zdarzeń
/**Zastąpiono, dzięki czemu możemy zakończyć działanie po zamknięciu okna*/
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
Twórca wskazał, że klasa ta będzie obsługiwać zdarzenia okna. Zadanie to realizuje metoda processWindowEvent. Najpierw przekazuje ona do swojej klasy nadrzędnej (JFrame) otrzymane zdarzenie WindowEvent, a następnie, jeśli jest to zdarzenie WINDOW_CLOSING wywołane kliknięciem przycisku zamykania okna, aplikacja zostaje zamknięta.
5.2.2.2.5. Wniosek
Kod klasy okna różni się od tego przedstawionego w przykładzie na początku rozdziału. Gdybyśmy korzystali z innego narzędzia do generowania kodu Java niż JBuilder, mielibyśmy zapewne jeszcze inny kod. W praktyce zaakceptujemy kod wygenerowany przez JBuilder do utworzenia okna, aby skupić się wyłącznie na pisaniu procedur obsługi zdarzeń interfejsu graficznego.
5.2.3. Tworzenie interfejsu graficznego
5.2.3.1. Przykład
W poprzednim przykładzie nie umieściliśmy żadnych komponentów w oknie. Teraz zbudujmy okno z przyciskiem, etykietą i polem wprowadzania danych:

Pola są następujące:
nr | nazwa | typ | rola |
1 | lblSaisie | JLabel | nazwa |
2 | txtSaisie | JTextField | pole wprowadzania danych |
3 | cmdAfficher | JButton | w celu wyświetlenia zawartości pola wprowadzania danych w oknie dialogowym txtSaisie |
Postępując tak samo jak w przypadku poprzedniego projektu, utwórz projekt interface2.jpr, nie umieszczając na razie żadnych komponentów w oknie.

W powyższym oknie wybierz klasę interface2.java. Po prawej stronie tego okna znajduje się segregator z zakładkami:

Zakładka Source zapewnia dostęp do kodu źródłowego klasy interface2.java. Zakładka Conception umożliwia wizualne tworzenie okna. Wybierz tę zakładkę. Przed sobą masz kontener okna, w którym umieścisz komponenty. Na razie jest on pusty. W lewym oknie wyświetlana jest struktura klasy:

this | oznacza okno |
contentPane | jego kontener, w którym będą umieszczane komponenty, a także sposób rozmieszczenia tych komponentów w kontenerze (domyślnie BorderLayout) |
borderLayout1 | instancję menedżera formatowania |
Wybierz obiekt this. Po prawej stronie pojawi się okno jego właściwości:

Na niektóre z tych właściwości należy zwrócić uwagę:
background | służy do ustawienia koloru tła okna |
foreground | do ustawienia koloru elementów graficznych w oknie |
JMenuBar | do przypisania menu do okna |
title | aby nadać oknu tytuł |
resizable | do określenia typu okna |
font | w celu ustawienia czcionki tekstu wyświetlanego w oknie |
Gdy obiekt this jest nadal zaznaczony, można zmienić rozmiar kontenera wyświetlanego na ekranie, przeciągając punkty kotwiczące znajdujące się wokół kontenera:

Jesteśmy teraz gotowi do umieszczenia komponentów w powyższym kontenerze. Najpierw jednak zmienimy menedżera formatowania. Wybierz obiekt contentPane w oknie struktury:

Następnie w oknie właściwości tego obiektu wybierz właściwość layout i spośród dostępnych wartości wybierz wartość null:

Brak menedżera formatowania pozwoli nam na swobodne rozmieszczanie komponentów w kontenerze. Nadszedł czas, aby je wybrać.
Po zaznaczeniu panelu Conception komponenty są dostępne w segregatorze z zakładkami u góry okna projektowego:

Do zbudowania interfejsu graficznego mamy do dyspozycji komponenty swing (1) oraz komponenty awt (2). W tym przypadku wykorzystamy komponenty swing. Na pasku komponentów powyżej wybierz komponent JLabel (3), komponent JTextField (4) oraz komponent JButton (5) i umieść je w kontenerze okna projektowego.

Teraz dostosujmy każdy z tych trzech komponentów:
- etykietę (JLabel) jLabel1
Zaznacz komponent, aby wyświetlić okno właściwości. W tym oknie zmień następujące właściwości: nazwa: lblSaisie, tekst: Wpisz
- pole wprowadzania danych (JTextField) jTextfield1
Zaznacz komponent, aby wyświetlić okno jego właściwości. W tym oknie zmień następujące właściwości: name: txtSaisie, text: nie wpisuj niczego
- przycisk (JButton): nazwa: cmdAfficher, tekst: Wyświetl
Otrzymujemy teraz następujące okno:

oraz następującą strukturę:

Możemy uruchomić (F9) nasz projekt, aby uzyskać pierwszy podgląd działania okna:

Zamknij okno. Pozostaje nam jeszcze napisać procedurę powiązaną z kliknięciem przycisku Afficher. Zaznacz przycisk, aby uzyskać dostęp do jego okna właściwości. Okno to ma dwie zakładki: propriétés i événements. Wybierz événements.

W lewej kolumnie okna wyświetlona jest lista możliwych zdarzeń związanych z przyciskiem. Kliknięcie przycisku odpowiada zdarzeniu actionPerformed. Prawa kolumna zawiera nazwę procedury wywoływanej w momencie wystąpienia odpowiedniego zdarzenia. Kliknij komórkę po prawej stronie zdarzenia actionPerformed:

JBuilder generuje domyślną nazwę dla każdego obsługi zdarzenia w postaci nomComposant_nomEvénement, w tym przypadku cmdAfficher_actionPerformed. Można usunąć domyślną nazwę i wpisać inną. Aby uzyskać dostęp do kodu obsługi zdarzenia cmdAfficher_actionPerformed, wystarczy dwukrotnie kliknąć na jej nazwę powyżej. Następnie automatycznie przechodzi się do panelu źródłowego klasy, w którym wyświetlany jest szkielet kodu obsługi zdarzenia:
Pozostaje nam tylko uzupełnić ten kod. W tym przypadku chcemy wyświetlić okno dialogowe zawierające zawartość pola txtSaisie:
void cmdAfficher_actionPerformed(ActionEvent e) {
JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(),
"Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
}
JOptionPane to klasa biblioteki javax.swing. Umożliwia ona wyświetlanie komunikatów wraz z ikoną lub żądanie informacji od użytkownika. W tym przypadku wykorzystujemy statyczną metodę tej klasy:

parentComponent | obiekt-kontener „nadrzędny” okna dialogowego: w tym przypadku this. |
komunikat | obiekt do wyświetlenia. W tym przypadku zawartość pola wprowadzania danych |
title | tytuł okna dialogowego |
messageType | typ komunikatu do wyświetlenia. Określa ikonę, która zostanie wyświetlona w polu obok komunikatu. Możliwe wartości: INFORMATION_MESSAGE, QUESTION_MESSAGE, ERROR_MESSAGE, WARNING_MESSAGE, PLAIN_MESSAGE |
Uruchommy naszą aplikację (F9):


5.2.3.2. Kod klasy okna
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();
/**Utwórz ramkę*/
public interface2() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Zainicjowanie komponentu*/
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);
}
/**Zastąpiono, dzięki czemu możemy zakończyć działanie po zamknięciu okna*/
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. Atrybuty
JPanel contentPane;
JLabel lblSaisie = new JLabel();
JTextField txtSaisie = new JTextField();
JButton cmdAfficher = new JButton();
Znajduje się tam pojemnik na komponenty typu JPanel oraz trzy komponenty.
5.2.3.2.2. Producent
/**Utwórz ramkę*/
public interface2() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Zainicjowanie komponentu*/
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);
}
Konstruktor interface2 jest podobny do konstruktora poprzedniego analizowanego interfejsu graficznego. Różnice występują w metodzie jbInit: kod tworzenia okna zależy od umieszczonych w nim komponentów. Można wykorzystać kod z jbInit, dodając do niego własne komentarze:
private void jbInit() throws Exception {
// sam okno (rozmiar, tytuł)
this.setSize(new Dimension(304, 129));
this.setTitle("Saisies & boutons - 1");
// kontener komponentów
contentPane = (JPanel) this.getContentPane();
// brak menedżera formatowania dla tego kontenera
contentPane.setLayout(null);
// etykieta lblSaisie (nazwa, pozycja, rozmiar)
lblSaisie.setText("Saisie");
lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
// pole wprowadzania danych (pozycja, rozmiar)
txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
// przycisk „Pokaż” (etykieta, pozycja, rozmiar)
cmdAfficher.setText("Afficher");
cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
// menedżer zdarzeń przycisku
cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
cmdAfficher_actionPerformed(e);
}
});
// dodanie 3 komponentów do kontenera
contentPane.add(lblSaisie, null);
contentPane.add(txtSaisie, null);
contentPane.add(cmdAfficher, null);
}//jbInit
Warto zwrócić uwagę na dwie kwestie:
- kod ten mógłby zostać napisany ręcznie. Oznacza to, że do stworzenia interfejsu graficznego można obejść się bez programu JBuilder.
- sposób, w jaki przypisano procedurę obsługi zdarzeń przycisku cmdAfficher. Procedura obsługi zdarzeń komponentu cmdAfficher mogłaby zostać zadeklarowana za pomocą cmdAfficher.addActionListener(new handler()) gdzie gestionnaire byłaby klasą zawierającą publiczną metodę actionPerformed odpowiedzialną za obsługę kliknięcia przycisku Afficher. W tym przypadku JBuilder wykorzystuje jako handler instancję klasy anonimowej:
new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
cmdAfficher_actionPerformed(e);
}
Tworzona jest nowa instancja interfejsu ActionListener, a zaraz potem definiowana jest jej metoda actionPerformed. Metoda ta ogranicza się do wywołania metody klasy interface2. Wszystko to jest jedynie zabiegiem mającym na celu zdefiniowanie w tej samej klasie co okno procedur obsługi zdarzeń komponentów tego okna. Można by postąpić inaczej:
co powoduje, że metoda actionPerformed będzie wyszukiwana w this, czyli w klasie okna. Ta druga metoda wydaje się prostsza, ale pierwsza ma nad nią przewagę: pozwala na stosowanie różnych procedur obsługi dla różnych przycisków, podczas gdy druga metoda tego nie umożliwia. W tym ostatnim przypadku bowiem jedyna metoda actionPeformed musi obsługiwać kliknięcia różnych przycisków, a zatem przed rozpoczęciem działania musi najpierw zidentyfikować, który z nich wywołał zdarzenie.
5.2.3.2.3. Obsługa zdarzeń
Są to te, które już omówiliśmy:
/**Zastąpiono, dzięki czemu możemy zamknąć okno, gdy zostanie ono zamknięte*/
protected void processWindowEvent(WindowEvent e) {
super.processWindowEvent(e);
if (e.getID() == WindowEvent.WINDOW_CLOSING) {
System.exit(0);
}
}
// kliknięcie przycisku „Pokaż”
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
Na podstawie dwóch analizowanych projektów można stwierdzić, że po stworzeniu interfejsu graficznego za pomocą JBuilder zadaniem programisty jest napisanie procedur obsługi zdarzeń, które mają być obsługiwane przez ten interfejs graficzny.
5.2.4. Szukanie pomocy
W przypadku języka Java często potrzebna jest pomoc, zwłaszcza ze względu na bardzo dużą liczbę dostępnych klas. Poniżej podajemy kilka wskazówek, jak znaleźć pomoc dotyczącą danej klasy. Należy wybrać opcję Pomoc/Tematy pomocy z menu.

Ekran pomocy zazwyczaj składa się z dwóch okien:
- lewe, w którym wpisuje się, czego się szuka. Zawiera ono trzy zakładki: Sommaire, Index i Chercher.
- prawe okno, w którym wyświetlane są wyniki wyszukiwania
Dostępna jest pomoc dotycząca korzystania z pomocy programu JBuilder. W pomocy programu JBuilder wybierz opcję Pomoc/Korzystanie z pomocy. Znajdziesz tam wyjaśnienie, jak korzystać z pomocy. Zostaną tam na przykład przedstawione różne elementy przeglądarki pomocy:

Przyjrzyjmy się nieco bliżej stronom Sommaire i Index.
5.2.4.1. Pomoc: Spis treści

5.2.4.1.1. Spis treści: Wprowadzenie do języka Java
Znajdziemy tu podstawowe elementy języka Java, ale nie tylko, jak pokazuje lista tematów poruszanych w ramach tej opcji:

5.2.4.1.2. Spis treści: Samouczki
Jeśli wybierzemy opcję „Samouczki” w powyższym spisie treści, w oknie po prawej stronie wyświetli się lista dostępnych samouczków:

Podstawowe samouczki są szczególnie przydatne na początku pracy z JBuilderem. Oprócz tych przedstawionych powyżej istnieje wiele innych, a przed rozpoczęciem tworzenia aplikacji warto sprawdzić, czy nie ma samouczka, który mógłby nam pomóc.
5.2.4.1.3. Spis treści: JDK
Wybierając opcję Java 2 JDK 1.3, uzyskuje się dostęp do wszystkich bibliotek JDK. Zazwyczaj nie jest to miejsce, w którym należy szukać informacji o konkretnej klasie, jeśli nie wiadomo, w której bibliotece się ona znajduje. Natomiast opcja ta jest przydatna, jeśli zależy nam na uzyskaniu ogólnego przeglądu bibliotek Javy.
5.2.4.2. Pomoc: Indeks
Wybierz zakładkę Indeks w lewym oknie pomocy. Ta opcja pozwala na przykład znaleźć pomoc dotyczącą konkretnej klasy. Załóżmy na przykład, że chcesz poznać metody pól wprowadzania danych swing i JTextField. Wpisz „JTextField” w polu wyszukiwania:
![]()
Pomoc wyświetli wpisy indeksu zaczynające się od wpisanej frazy:

Teraz wystarczy dwukrotnie kliknąć interesujący Cię wpis, w tym przypadku JTextField class. Pomoc dotycząca tej klasy wyświetli się wówczas w prawym oknie:

Zostanie wyświetlony pełny opis klasy.
5.2.5. Niektóre komponenty Swing
Poniżej przedstawiamy różne zastosowania wykorzystujące najpopularniejsze komponenty swing, aby zapoznać się z ich głównymi metodami i właściwościami. W przypadku każdego zastosowania przedstawiamy interfejs graficzny oraz kod, w szczególności kod modułów obsługi zdarzeń.
5.2.5.1. Komponenty JLabel i JTextField
Z tymi dwoma komponentami mieliśmy już do czynienia. JLabel to komponent tekstowy, a JTextField to komponent pola wprowadzania danych. Ich dwie główne metody to
String getText() | , służąca do pobrania zawartości pola wprowadzania danych lub tekstu etykiety |
void setText(String unTexte) | służąca do umieszczenia unTexte w polu lub etykiecie |
Zdarzenia zwykle używane dla JTextField to:
actionPerformed | sygnalizuje, że użytkownik zatwierdził (klawiszem Enter) wprowadzony tekst |
caretUpdate | oznacza, że użytkownik przesunął kursor |
inputMethodChanged | sygnalizuje, że użytkownik zmienił zawartość pola wprowadzania danych |
Oto przykład wykorzystujący zdarzenie caretUpdate do śledzenia zmian w polu wprowadzania danych:

nr | typ | nazwa | rola |
1 | JTextField | txtSaisie | pole wprowadzania danych |
2 | JTextField | txtControle | wyświetla tekst z pola 1 w czasie rzeczywistym |
3 | JButton | cmdEffacer | w celu wyczyszczenia pól 1 i 2 |
4 | JButton | cmdQuitter | aby zamknąć aplikację |
Odpowiedni kod tej aplikacji wygląda następująco:
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();
/**Utwórz ramkę*/
public Cadre1() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Zainicjuj komponent*/
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);
}
});
....
}
/**Zastąpiono, dzięki czemu możemy zakończyć działanie po zamknięciu okna*/
protected void processWindowEvent(WindowEvent e) {
...
}
void txtSaisie_caretUpdate(CaretEvent e) {
// kursor wprowadzania danych został przesunięty
txtControle.setText(txtSaisie.getText());
}
void CmdQuitter_actionPerformed(ActionEvent e) {
// wychodzimy z aplikacji
System.exit(0);
}
void CmdEffacer_actionPerformed(ActionEvent e) {
// kasujemy zawartość pola wprowadzania danych
txtSaisie.setText("");
}
}
Oto przykładowe działanie:

5.2.5.2. komponent JComboBox


Komponent JComboBox to lista rozwijana połączona z polem wprowadzania danych: użytkownik może albo wybrać element z (2), albo wpisać tekst w (1). Domyślnie komponenty JComboBox nie są edytowalne. Aby umożliwić edycję, należy jawnie wywołać metodę setEditable(true). Aby zapoznać się z klasą JComboBox, wpisz JComboBox w indeksie pomocy.
Obiekt JComboBox można utworzyć na różne sposoby:
new JComboBox() | tworzy puste pole rozwijane |
new JComboBox (Object[] items) | tworzy listę rozwijaną zawierającą tablicę obiektów |
new JComboBox(Vector items) | to samo z wektorem obiektów |
Można się zdziwić, że pole kombi może zawierać obiekty, podczas gdy zazwyczaj zawiera ciągi znaków. Pod względem wizualnym tak właśnie będzie. Jeśli obiekt JComboBox zawiera obiekt obj, wyświetla ciąg znaków obj.toString(). Należy pamiętać, że każdy obiekt posiada metodę toString odziedziczoną po klasie Object, która zwraca ciąg znaków „reprezentujący” ten obiekt.
Przydatne metody klasy JCombobox to:
void addItem(Object unObjet) | dodaje obiekt do listy rozwijanej |
int getItemCount() | zwraca liczbę elementów listy rozwijanej |
Object getItemAt(int i) | zwraca obiekt o numerze i z listy rozwijanej |
void insertItemAt(Object unObjet, int i) | wstawia unObjet w pozycji i listy rozwijanej |
int getSelectedIndex() | zwraca numer wybranego elementu w liście rozwijanej |
Object getSelectedItem() | zwraca obiekt wybrany w liście rozwijanej |
void setSelectedIndex(int i) | wybiera element o indeksie i z listy rozwijanej |
void setSelectedItem(Object unObjet) | wybiera obiekt określony w liście rozwijanej |
void removeAllItems() | czyści listę rozwijaną |
void removeItemAt(int i) | usuwa element o numerze i z listy rozwijanej |
void removeItem(Object unObjet) | usuwa określony obiekt z listy rozwijanej |
void setEditable(boolean val) | ustawia listę rozwijaną jako edytowalną (val=true) lub nieedytowalną (val=false) |
Podczas wyboru elementu z listy rozwijanej występuje zdarzenie actionPerformed, które można wykorzystać do otrzymania powiadomienia o zmianie wyboru w liście rozwijanej. W poniższej aplikacji wykorzystujemy to zdarzenie do wyświetlenia elementu, który został wybrany z listy.

Przedstawiamy tylko kod dotyczący okna.
public class Cadre1 extends JFrame {
JPanel contentPane;
JComboBox jComboBox1 = new JComboBox();
JLabel jLabel1 = new JLabel();
/**Tworzenie ramki*/
public Cadre1() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
// przetwarzanie – wypełnianie listy rozwijanej
String[] infos={"un","deux","trois","quatre"};
for(int i=0;i<infos.length;i++)
jComboBox1.addItem(infos[i]);
}
/**Inicjalizacja komponentu*/
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) {
// wybrano nowy element – wyświetla się
JOptionPane.showMessageDialog(this,jComboBox1.getSelectedItem(),
"actionPerformed",JOptionPane.INFORMATION_MESSAGE);
}
}
5.2.5.3. komponent JList
Komponent Swing JList jest bardziej złożony niż jego odpowiednik z biblioteki awt. Istnieją dwie istotne różnice:
- zawartość listy jest zarządzana przez obiekt inny niż sama lista. W tym przypadku wykorzystamy obiekt DefaultListModel, który działa podobnie jak Vector, ale dodatkowo powiadamia obiekt JList o każdej zmianie zawartości, dzięki czemu zmienia się również wizualne wyświetlanie listy.
- Domyślnie lista nie przewija się. Należy umieścić listę w kontenerze ScrollPane, który umożliwia przewijanie.
W kodzie źródłowym listę można zdefiniować w następujący sposób:
// wektor wartości z listy
DefaultlistModel valeurs=new DefaultListModel();
// sama lista, z którą kojarzony jest wektor jej wartości
JList jList1 = new JList(valeurs);
// przewijany kontener, w którym umieszczamy listę, aby uzyskać listę przewijaną
JScrollPane jScrollPane1 = new JScrollPane(jList1);
Aby dołączyć listę jList1 do kontenera jScrollPane1, kod wygenerowany przez JBuilder działa inaczej:
- deklaracja kontenera w atrybutach okna
- następnie w kodzie jbInit lista jest powiązana z kontenerem
Aby dodać wartości do powyższej listy JList1, wystarczy dodać je do jej wektora wartości valeurs:
w wyniku czego pojawi się następujące okno:

Jak zbudowany jest ten interfejs?
- wybieramy komponent JScrollPane na stronie „Kontenery Swing” komponentów i przeciągamy go do okna, dostosowując jego rozmiar do pożądanych wymiarów
- wybieramy komponent JList na stronie „Swing” w sekcji komponentów i umieszczamy go w kontenerze JScrollPane, gdzie zajmuje on całą dostępną przestrzeń.
Kod wygenerowany przez JBuilder należy nieznacznie zmodyfikować, aby uzyskać następujący kod:
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();
/**Tworzenie ramki*/
public interfaceAppli() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
// przetwarzanie
// wstawiamy listę do scrollPane
// inicjowanie listy
for(int i=0;i<10;i++)
valeurs.addElement(""+i);
}
/**Inicjalizacja komponentu*/
private void jbInit() throws Exception {
....
// lista jList1 jest powiązana z kontenerem jcrollPane1
jScrollPane1.getViewport().add(jList1, null);
}
/**Zastąpiono, dzięki czemu możemy zakończyć działanie po zamknięciu okna*/
protected void processWindowEvent(WindowEvent e) {
....
}
}
Przyjrzyjmy się teraz głównym metodom klasy JList, wyszukując JList w indeksie pomocy. Obiekt JList można utworzyć na różne sposoby:

Prostą metodą jest ta, z której skorzystaliśmy: utworzenie pustego obiektu DefaultListModel V, a następnie powiązanie go z listą, którą chcemy utworzyć, za pomocą polecenia new JList(V). Zawartość listy nie jest zarządzana przez obiekt JList, lecz przez obiekt zawierający wartości listy. Jeśli zawartość została utworzona przy użyciu obiektu DefaultListModel opartego na klasie Vector, do dodawania, wstawiania i usuwania elementów z listy można wykorzystać metody klasy Vector. Lista może umożliwiać wybór pojedynczy lub wielokrotny. Określa to metoda setSelectionMode:

Aktualny tryb wyboru można sprawdzić za pomocą metody getSelectionMode:
![]()
Wybrany element lub elementy można uzyskać za pomocą następujących metod:

Wiemy, jak powiązać wektor wartości z listą za pomocą konstruktora JList(DefaultListModel). I odwrotnie, obiekt DefaultListModel z listy JList można uzyskać za pomocą:

Wiemy już wystarczająco dużo, aby napisać następującą aplikację:

Elementy tego okna są następujące:
nr | typ | nazwa | rola |
1 | JTextField | txtSaisie | pole wprowadzania danych |
2 | JList | jList1 | lista zawarta w kontenerze jScrollPane1 |
3 | JList | jList2 | lista zawarta w kontenerze jScrollPane2 |
4 | JButton | cmd1To2 | przenosi zaznaczone elementy z listy 1 do listy 2 |
5 | JButton | cmd2To1 | wykonuje operację odwrotną |
6 | JButton | cmdRaz1 | wyczyść listę 1 |
7 | JButton | cmdRaz2 | wyczyść listę 2 |
Użytkownik wpisuje tekst w polu (1) i zatwierdza go. Następnie w polu wprowadzania danych występuje zdarzenie actionPerformed, które służy do dodania wprowadzonego tekstu do listy 1. Oto kod przydatny do realizacji tej pierwszej funkcji:
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();
/**Utwórz ramkę*/
public interfaceAppli() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}//interfaceAppli
/**Zainicjuj komponent*/
private void jbInit() throws Exception {
...
txtSaisie.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
txtSaisie_actionPerformed(e);
}
});
...
// Jlist1 jest umieszczony w kontenerze jScrollPane1
jScrollPane1.getViewport().add(jList1, null);
// Jlist2 jest umieszczony w kontenerze jScrollPane2
jScrollPane2.getViewport().add(jList2, null);
...
}
/**Zastąpiono, dzięki czemu możemy zakończyć działanie po zamknięciu okna*/
protected void processWindowEvent(WindowEvent e) {
...
}
void txtSaisie_actionPerformed(ActionEvent e) {
// tekst wprowadzony został zatwierdzony
// odbieramy go po usunięciu spacji na początku i na końcu
String texte=txtSaisie.getText().trim();
// jeśli jest pusty, nie potrzebujemy go
if(texte.equals("")){
// komunikat o błędzie
JOptionPane.showMessageDialog(this,"Vous devez taper un texte",
"Erreur",JOptionPane.WARNING_MESSAGE);
// koniec
return;
}//if
// jeśli nie jest puste, dodajemy je do wartości z listy 1
v1.addElement(texte);
// i czyścimy pole wprowadzania danych
txtSaisie.setText("");
}/// txtSaisie_actionperformed
}//klasa
Kod służący do przeniesienia wybranych elementów z jednej listy do drugiej jest następujący:
void cmd1To2_actionPerformed(ActionEvent e) {
// przeniesienie wybranych elementów z listy 1 do listy 2
transfert(jList1,jList2);
}//cmd1To2
void cmd2To1_actionPerformed(ActionEvent e) {
// przeniesienie wybranych elementów z jList2 do jList1
transfert(jList2,jList1);
}//cmd2TO1
private void transfert(JList L1, JList L2){
// przeniesienie elementów zaznaczonych na liście 1 do listy 2
// pobieramy tablicę indeksów elementów zaznaczonych w L1
int[] indices=L1.getSelectedIndices();
// co należy zrobić?
if (indices.length==0) return;
// pobieramy wartości z L1
DefaultListModel v1=(DefaultListModel)L1.getModel();
// oraz z pliku L2
DefaultListModel v2=(DefaultListModel)L2.getModel();
for(int i=indices.length-1;i>=0;i--){
// do L2 dodajemy wartości wybrane z L1
v2.addElement(v1.elementAt(indices[i]));
// elementy z L1 skopiowane do L2 muszą zostać usunięte z L1
v1.removeElementAt(indices[i]);
}//dla
}//przeniesienie
Kod powiązany z przyciskami Raz jest niezwykle prosty:
void cmdRaz1_actionPerformed(ActionEvent e) {
// wyczyść listę 1
v1.removeAllElements();
}//polecenie Raz1
void cmdRaz2_actionPerformed(ActionEvent e) {
// wyczyść listę 2
v2.removeAllElements();
}///polecenie Raz2
5.2.5.4. Pola wyboru JCheckBox, przyciski opcji JButtonRadio
Zamierzamy napisać następującą aplikację:

Elementy okna są następujące:
nr | typ | nazwa | rola |
1 | JButtonRadio | jButtonRadio1 jButtonRadio2 jButtonRadio3 | 3 przyciski opcji należące do grupy buttonGroup1 |
2 | JCheckBox | jCheckBox1 jCheckBox2 jCheckBox3 | 3 pola wyboru |
3 | JList | jList1 | lista w kontenerze jScrollPane1 |
4 | ButtonGroup | buttonGroup1 | element niewidoczny – służy do zgrupowania trzech przycisków opcji, tak aby po podświetleniu jednego z nich pozostałe wygasły. |
Grupę przycisków opcji można utworzyć w następujący sposób:
- umieszcza się każdy z przycisków opcji, nie zwracając uwagi na ich grupowanie
- umieszczamy w kontenerze komponent Swing o nazwie ButtonGroup. Komponent ten jest niewidoczny. Nie pojawia się więc w kreatorze okna. Widoczny jest jednak w jego strukturze:

Powyżej, w gałęzi Autre, widoczne są niewidoczne atrybuty okna. Po utworzeniu grupy przycisków opcji można przypisać do niej poszczególne przyciski opcji. W tym celu należy wybrać właściwości przycisku opcji:

a w właściwości buttonGroup przycisku opcji należy wpisać nazwę grupy, do której chcemy przypisać przycisk opcji, w tym przypadku buttonGroup1. Czynność tę powtarzamy dla wszystkich trzech przycisków opcji.
Główną metodą przycisków opcji i pól wyboru jest metoda isSelected(), która wskazuje, czy pole lub przycisk jest zaznaczony. Tekst powiązany z komponentem można uzyskać za pomocą metody getText(), a ustawić za pomocą metody setText(String unTexte). Pole wyboru lub przycisk opcji można zaznaczyć za pomocą metody setSelected(boolean value).
Po kliknięciu przycisku opcji lub pola wyboru wyzwalane jest zdarzenie actionPerformed. W poniższym kodzie wykorzystujemy to zdarzenie do śledzenia zmian wartości przycisków opcji i pól wyboru:
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);
/**Utwórz ramkę*/
public interfaceAppli() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Zainicjuj komponent*/
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");
// przyciski opcji są zgrupowane
buttonGroup1.add(jRadioButton1);
buttonGroup1.add(jRadioButton2);
buttonGroup1.add(jRadioButton3);
// pola wyboru
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);
}
});
....
}
/**Zastąpiono, dzięki czemu możemy zakończyć działanie po zamknięciu okna*/
protected void processWindowEvent(WindowEvent e) {
...
}
private void afficheRadioButtons(ActionEvent e){
// wyświetla wartości z 3 przycisków opcji
valeurs.addElement("boutons radio=("+jRadioButton1.isSelected()+","+
jRadioButton2.isSelected()+","+jRadioButton3.isSelected()+")");
}//afficheRadioButtons
void afficheCases(ActionEvent e) {
// wyświetla wartości pól wyboru
valeurs.addElement("cases à cocher=["+jCheckBox1.isSelected()+","+
jCheckBox2.isSelected()+","+jCheckBox3.isSelected()+")");
}//afficheCases
}//sortuje
Oto przykładowe wykonanie:

5.2.5.5. komponent JScrollBar
Stwórzmy następującą aplikację:

nr | typ | nazwa | rola |
1 | JScrollBar | jScrollBar1 | przesuw poziomy |
2 | JScrollBar | jScrollBar2 | regulator pionowy |
3 | JTextField | txtvaleurHS | wyświetla wartość regulatora poziomego 1 – umożliwia również ustalenie tej wartości |
4 | JTextField | txtvaleurVS | wyświetla wartość suwaka pionowego 2 – umożliwia również ustalenie tej wartości |
- Regulator JScrollBar umożliwia użytkownikowi wybór wartości z zakresu wartości całkowitych, symbolizowanego przez „pasek” regulatora, po którym porusza się kursor.
- W przypadku suwaka poziomego lewy koniec oznacza minimalną wartość zakresu, prawy koniec – wartość maksymalną, a suwak – aktualnie wybraną wartość. W przypadku suwaka pionowego minimum odpowiada górnemu końcowi, a maksimum – dolnemu końcowi. Para (min, max) ma domyślną wartość (0,100).
- Kliknięcie na skrajach suwaka powoduje zmianę wartości o jeden przyrost (dodatni lub ujemny) w zależności od klikniętego końca o nazwie unitIncrement, którego domyślną wartością jest 1.
- Kliknięcie po obu stronach suwaka powoduje zmianę wartości o jeden przyrost (dodatni lub ujemny) w zależności od klikniętego końca o nazwie blockIncrement, którego domyślną wartością jest 10.
- Te pięć wartości (min, max, wartość, unitIncrement, blockIncrement) można uzyskać za pomocą metod getMinimum(), getMaximum(), getValue(), getUnitIncrement(), getBlockIncrement(), z których wszystkie zwracają liczbę całkowitą i mogą być ustawione za pomocą metod setMinimum(int min), setMaximum(int max), setValue(int val), setUnitIncrement(int uInc), setBlockIncrement(int bInc)
Podczas korzystania z komponentów JScrollBar należy pamiętać o kilku kwestiach. Po pierwsze, komponent ten znajduje się na pasku komponentów Swing:

Po umieszczeniu go w kontenerze domyślnie jest on ustawiony w orientacji pionowej. Orientację poziomą można ustawić za pomocą poniższej właściwości orientation:

Na powyższym arkuszu właściwości widać, że mamy dostęp do właściwości minimum, maximum, value, unitIncrement, blockIncrement obiektu JScrollbar. Można je zatem ustawić na etapie projektowania. Po umieszczeniu paska przewijania w kontenerze jego „pasmo zmiany” nie pojawia się:

Problem ten można rozwiązać, nadając komponentowi obramowanie. Odbywa się to za pomocą właściwości border, która może przyjmować różne wartości:

Oto przykładowy efekt dla wartości RaisedBevel:
![]()
Po kliknięciu górnego końca suwaka pionowego jego wartość maleje. Może to zaskoczyć przeciętnego użytkownika, który zazwyczaj oczekuje, że wartość będzie „rosła”. Problem ten rozwiązuje się, nadając ujemną wartość właściwościom unitIncrement i blockIncrement.
Jak śledzić zmiany wartości suwaka? Gdy wartość suwaka ulega zmianie, generowane jest zdarzenie adjustmentValueChanged. Wystarczy powiązać procedurę z tym zdarzeniem, aby otrzymywać powiadomienia o każdej zmianie wartości suwaka.

Poniżej znajduje się kod naszej aplikacji:
....
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;
/**Tworzenie ramki*/
public cadreAppli() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Zainicjowanie komponentu*/
private void jbInit() throws Exception {
...
// ramka dla pasków przewijania
border1 = BorderFactory.createBevelBorder(BevelBorder.RAISED,Color.white,Color.white,new Color(134, 134, 134),new Color(93, 93, 93));
// brak tytułu na ramce
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);
}
});
......
}
/**Zastąpiono, dzięki czemu możemy zamknąć okno*/
protected void processWindowEvent(WindowEvent e) {
...
}
void jScrollBar1_adjustmentValueChanged(AdjustmentEvent e) {
// zmieniła się wartość paska przewijania 1
txtValeurHS.setText(""+jScrollBar1.getValue());
}
void jScrollBar2_adjustmentValueChanged(AdjustmentEvent e) {
// zmieniła się wartość paska przewijania 2
txtValeurVS.setText(""+jScrollBar2.getValue());
}
void txtValeurHS_actionPerformed(ActionEvent e) {
// ustalamy wartość poziomego paska przewijania
setValeur(jScrollBar1,txtValeurHS);
}
void txtValeurVS_actionPerformed(ActionEvent e) {
// ustalamy wartość pionowego paska przewijania
setValeur(jScrollBar2,txtValeurVS);
}
private void setValeur(JScrollBar jS, JTextField jT){
// ustala wartość paska przewijania jS na podstawie tekstu z pola jT
int valeur=0;
try{
valeur=Integer.parseInt(jT.getText());
jS.setValue(valeur);
}
catch (Exception e){
// wyświetla się komunikat o błędzie
afficher(""+e);
}//try-catch
}//setValeur
void afficher(String message){
// wyświetla komunikat w oknie
JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
}//wyświetla
}
Oto przykładowe wykonanie:

5.2.5.6. komponent JTextArea
Komponent JTextArea umożliwia wprowadzenie kilku wierszy tekstu, w przeciwieństwie do komponentu JTextField, w którym można wprowadzić tylko jeden wiersz. Jeśli ten komponent zostanie umieszczony w kontenerze z przewijaniem (JScrollPane), otrzymujemy pole tekstowe z przewijaniem. Tego typu komponent można spotkać na przykład w aplikacji pocztowej, gdzie tekst wiadomości do wysłania byłby wpisywany w komponencie JTextArea. Typowe metody to String getText() do sprawdzenia zawartości pola tekstowego oraz setText(String unTexte) do umieszczenia unTexte w polu tekstowym oraz append(String unTexte) do dodania unTexte do tekstu już znajdującego się w polu tekstowym. Rozważmy następującą aplikację:

nr | typ | nazwa | rola |
1 | JTextArea | txtTexte | pole tekstowe wielowierszowe |
2 | JButton | cmdAfficher | wyświetla zawartość pola 1 w oknie dialogowym |
3 | JButton | cmdEffacer | usuwa zawartość pola 1 |
4 | JTextField | txtAjout | tekst dodawany do tekstu z pola 1 po zatwierdzeniu klawiszem Enter. |
5 | JScrollPane | jScrollPane1 | przewijany kontener, w którym umieszczono pole tekstowe 1, aby uzyskać przewijane pole tekstowe. |
Odpowiedni kod wygląda następująco:
.....
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();
/**Tworzenie ramki*/
public cadreAppli() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Zainicjuj komponent*/
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);
}
/**Zastąpiono, dzięki czemu możemy zakończyć działanie po zamknięciu okna*/
protected void processWindowEvent(WindowEvent e) {
........
}
void cmdAfficher_actionPerformed(ActionEvent e) {
// wyświetla zawartość TextArea
afficher(txtTexte.getText());
}
void afficher(String message){
// wyświetla komunikat w okienku
JOptionPane.showMessageDialog(this,message,"Suivi",JOptionPane.INFORMATION_MESSAGE);
}// wyświetla
void cmdEffacer_actionPerformed(ActionEvent e) {
txtTexte.setText("");
}//cmdEffacer_actionPerformed
void txtAjout_actionPerformed(ActionEvent e) {
// dodawanie tekstu
txtTexte.append(txtAjout.getText());
// resetowanie i dodawanie
txtAjout.setText("");
}//
}
5.2.6. Zdarzenia związane z myszą
Podczas rysowania w kontenerze ważne jest, aby znać położenie myszy, na przykład w celu wyświetlenia punktu po kliknięciu. Przemieszczanie myszy powoduje wygenerowanie zdarzeń w kontenerze, w którym się porusza. Oto przykładowe zdarzenia oferowane przez JBuilder dla kontenera JPanel:

mouseClicked | kliknięcie myszą |
mouseDragged | mysz się przesuwa, lewy przycisk wciśnięty |
mouseEntered | mysz właśnie weszła w obszar kontenera |
mouseExited | mysz właśnie opuściła obszar kontenera |
mouseMoved | mysz się porusza |
mousePressed | Naciśnięcie lewego przycisku myszy |
mouseReleased | Zwolnienie lewego przycisku myszy |
Oto program pozwalający lepiej zrozumieć, w jakich momentach występują różne zdarzenia związane z myszą:

nr | typ | nazwa | rola |
1 | JTextField | txtPosition | w celu wyświetlenia pozycji myszy w kontenerze (ewentualnie MouseMoved) |
2 | JList | lstAffichage | aby wyświetlić zdarzenia myszy inne niż MouseMoved |
3 | JButton | cmdEffacer | aby skasować zawartość pola 2 |
Po uruchomieniu tego programu w przypadku kliknięcia otrzymujemy następujący wynik:

Zdarzenia są ułożone na liście od góry. Z powyższego zrzutu ekranu wynika więc, że jedno kliknięcie powoduje trzy zdarzenia, w następującej kolejności:
- MousePressed po naciśnięciu przycisku
- MouseReleased po zwolnieniu przycisku
- MouseClicked, co oznacza, że sekwencja dwóch poprzednich zdarzeń jest traktowana jako kliknięcie. Mogłoby to być podwójne kliknięcie. Jednak powyższa informacja clickCount=1 wskazuje, że jest to pojedyncze kliknięcie.
Teraz, jeśli naciśniemy przycisk, przesuniemy mysz i zwolnimy przycisk:

Widzimy tu trzy zdarzenia:
- MousePressed – po początkowym naciśnięciu przycisku
- MouseDragged – podczas przesuwania myszy z wciśniętym przyciskiem
- MouseReleased po zwolnieniu przycisku
W obu powyższych przykładach widać, że zdarzenie myszy zawiera różne informacje, w tym współrzędne (x, y) myszy, na przykład (408,65) w pierwszym wierszu powyżej.
Kontynuując analizę, można zauważyć, że zdarzenie MouseExited jest wyzwalane, gdy tylko mysz opuści kontener lub najedzie na jeden z jego komponentów. W tym ostatnim przypadku kontener odbiera zdarzenie MouseExited, a komponent – zdarzenie MouseEntered. Odwrotna sytuacja ma miejsce, gdy mysz opuszcza komponent i wraca do kontenera.
Co się dzieje w przypadku dwukrotnego kliknięcia?

Mamy dokładnie te same zdarzenia, co w przypadku pojedynczego kliknięcia. Jedynie zdarzenie zawiera informację clickCount=2 (patrz wyżej), wskazującą, że faktycznie miało miejsce podwójne kliknięcie.
Kod tej aplikacji wygląda następująco:
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();
/**Utwórz ramkę*/
public Cadre1() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Zainicjowanie komponentu*/
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);
...............
}
/**Zastąpiono, dzięki czemu możemy zakończyć działanie po zamknięciu okna*/
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){
// wyświetla zdarzenie e na liście 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) {
// czyści listę
valeurs.removeAllElements();
}
}
5.2.7. Tworzenie okna z menu
Zobaczmy teraz, jak utworzyć okno z menu za pomocą JBuilder. Utworzymy następujące okno:


Utwórz nowy projekt, zaczynając od pustego okna. Z listy komponentów „Kontenery Swing” wybierz komponent JMenuBar (patrz rys. 1 poniżej) i umieść go w projektowanym oknie.

W oknie projektowym nic się nie wyświetla, ale komponent JMenuBar pojawia się w panelu struktury okna:

Kliknij dwukrotnie powyższy element jMenuBar1, aby uzyskać dostęp do menu w trybie projektowania:

1 | wstaw element menu |
2 | wstaw separator |
3 | wstawienie menu zagnieżdżonego |
4 | usuń element menu |
5 | wyłączenie pozycji menu |
6 | element menu z opcją zaznaczenia |
7 | odwrócić przycisk opcji |
Aby utworzyć swój pierwszy element menu, wpisz „Opcje A” w polu A powyżej, a następnie poniżej w następującej kolejności: A1, A2, separator, A3, A4.

Następnie obok:

Użyj narzędzia 3, aby zaznaczyć, że B3 jest zagnieżdżonym podmenu.
W miarę projektowania menu zmienia się logiczna struktura naszego okna:

Jeśli uruchomimy teraz naszą aplikację, zobaczymy puste okno bez menu. Musimy powiązać utworzone menu z naszym oknem. W tym celu w strukturze okna należy zaznaczyć obiekt this:

Uzyskasz wtedy dostęp do właściwości obiektu this:

Jedną z nich jest JMenuBar, która służy do ustalenia menu, które zostanie powiązane z oknem. Kliknij komórkę po prawej stronie JMenuBar. Zostaną wówczas wyświetlone wszystkie utworzone menu. W tym przypadku dostępny będzie tylko jMenuBar1. Wybierz go.
Uruchom aplikację (F9):

Teraz mamy menu, ale opcje na razie nic nie robią. Opcje menu są traktowane jak komponenty: mają właściwości i zdarzenia. W strukturze menu wybierz opcję jMenuItem1:

Uzyskasz wtedy dostęp do jej właściwości i zdarzeń:

Wybierz stronę zdarzeń i kliknij komórkę po prawej stronie zdarzenia actionPerformed: jest to zdarzenie, które ma miejsce po kliknięciu elementu menu. Domyślnie proponowana jest procedura przetwarzania. Kliknij ją dwukrotnie, aby uzyskać dostęp do jej kodu:

Napiszemy następujący prosty kod:
void jMenuItem1_actionPerformed(ActionEvent e) {
afficher("L'option A1 a été sélectionnée");
}
void afficher(String message){
// wyświetla komunikat w okienku
JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
}//wyświetla
Uruchom aplikację i wybierz opcję A1, aby wyświetlić następujący komunikat:

Kod źródłowy tej aplikacji wygląda następująco:
.....
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();
/**Tworzy ramkę*/
public Cadre1() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
/**Zainicjuj komponent*/
private void jbInit() throws Exception {
// okno jest powiązane z 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);
}
/**Zastąpiono, dzięki czemu możemy zakończyć działanie po zamknięciu okna*/
protected void processWindowEvent(WindowEvent e) {
....
}
void jMenuItem1_actionPerformed(ActionEvent e) {
afficher("L'option A1 a été sélectionnée");
}
void afficher(String message){
// wyświetla komunikat w okienku
JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
}//wyświetla
}
5.3. Okna dialogowe
5.3.1. Okna komunikatów
Wykorzystaliśmy już klasę JOptionPane do wyświetlania komunikatów. Tak więc poniższy kod:
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);
}
}
powoduje wyświetlenie następującego okienka:

Po zamknięciu tego okna znika ono, ale wątek, w którym było uruchomione, nie zostaje zatrzymany. Zjawisko to zazwyczaj nie występuje. Okna dialogowe są wykorzystywane w ramach aplikacji, która w pewnym momencie używa instrukcji System.exit(n) w celu zatrzymania wszystkich wątków. Należy o tym pamiętać w kolejnych przykładach, które są oparte na tym samym schemacie. W systemie DOS aplikację można przerwać za pomocą skrótu klawiszowego Ctrl-C. W przypadku instrukcji JBuilder należy użyć opcji „Uruchom/Zresetuj program” (Ctrl-F2). Ponadto pierwszym argumentem polecenia showMessageDialog jest tutaj null. Zazwyczaj tak nie jest. Zazwyczaj jest to raczej this, gdzie this oznacza główne okno aplikacji.
5.3.2. Wygląd i działanie
Wygląd powyższego okna może się różnić. Wygląd ten można skonfigurować za pomocą klasy javax.swing.UIManager. Kiedy komentowaliśmy kod wygenerowany przez JBuilder dla naszego pierwszego okna, natrafiliśmy na instrukcję, nad którą się nie zatrzymaliśmy:
Metoda setLookAndFeel klasy UIManager (UI = interfejs użytkownika) pozwala określić wygląd interfejsów graficznych. Klasa UIManager posiada metodę umożliwiającą sprawdzenie możliwych „wyglądów” interfejsów:
static UIManager.LookAndFeelInfo[] | getInstalledLookAndFeels() |
Metoda ta zwraca tablicę elementów typu LookAndFeelInfo. Klasa ta posiada metodę:
String | getClassName() |
która zwraca nazwę klasy „implementującej” dany wygląd. Wypróbujmy następujący program:
import javax.swing.*;
public class LookAndFeels {
// wyświetla dostępne motywy
public static void main(String[] args) {
// wyświetla listę zainstalowanych motywów
UIManager.LookAndFeelInfo[] lf=UIManager.getInstalledLookAndFeels();
// wyświetlanie
for(int i=0;i<lf.length;i++){
System.out.println(lf[i].getClassName());
}//dla
}//główne
}//klasyfikuje
Daje to następujące wyniki:
javax.swing.plaf.metal.MetalLookAndFeel
com.sun.java.swing.plaf.motif.MotifLookAndFeel
com.sun.java.swing.plaf.windows.WindowsLookAndFeel
Wydaje się więc, że istnieją trzy „różne” style. Wróćmy do naszego programu wyświetlającego komunikaty, wypróbowując różne możliwe style:
import javax.swing.*;
public class LookAndFeel2 {
// wyświetla dostępne motywy
public static void main(String[] args) {
// lista zainstalowanych motywów
UIManager.LookAndFeelInfo[] lf=UIManager.getInstalledLookAndFeels();
// wyświetlanie
for(int i=0;i<lf.length;i++){
// menedżer wyglądu
try{
UIManager.setLookAndFeel(lf[i].getClassName());
}catch(Exception ex){
System.err.println(ex.getMessage());
}//catch
// komunikat
JOptionPane.showMessageDialog(null,"Un message",lf[i].getClassName(),JOptionPane.INFORMATION_MESSAGE);
}//for
}//main
}//klasa
Wynikiem wykonania są następujące wyświetlenia:
![]() | ![]() | ![]() |
odpowiednio, od prawej do lewej: „styl” Metal, Motif, Windows.
5.3.3. Okna potwierdzenia
Klasa JOptionPane posiada metodę showConfirmDialog służącą do wyświetlania okienek potwierdzenia z przyciskami Oui, Non, Annuler. Istnieje kilka nadpisanych metod showConfirmDialog. Przyjrzyjmy się jednej z nich:
static int | showConfirmDialog(Component parentComponent, Object message, String title, int optionType) |
parentComponent | komponent nadrzędny okna dialogowego. Często jest to okno lub wartość null |
message | komunikat do wyświetlenia |
title | tytuł okna dialogowego |
optionType | JOptionPane.YES_NO_OPTION: przyciski „tak”, „nie” JOptionPane.YES_NO_CANCEL_OPTION: przyciski „tak”, „nie”, „anuluj” |
Wynik zwracany przez tę metodę to:
JOptionPane.YES_OPTION | użytkownik kliknął „tak” |
JOptionPane.NO_OPTION | użytkownik kliknął „nie” |
JOptionPane.CANCEL_OPTION | użytkownik kliknął „Anuluj” |
JOptionPane.CLOSED_OPTION | użytkownik zamknął okno |
Oto przykład:
import javax.swing.*;
public class confirm1 {
public static void main(String[] args) {
// wyświetla okna potwierdzenia
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));
}//strona główna
private static void affiche(int réponse){
// wskazuje, jaki rodzaj odpowiedzi otrzymano
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;
}//
}//wyświetla
}//klasyfikacja
![]() | ![]() |
Na konsoli wyświetlane są komunikaty Non i Annuler.
5.3.4. Pole wprowadzania danych
Klasa JOptionPane umożliwia również wprowadzanie danych za pomocą metody showInputDialog. Również w tym przypadku istnieje kilka nadpisanych metod. Przedstawiamy jedną z nich:
static String | showInputDialog(Component parentComponent, Object message, String title, int messageType) |
Argumenty są takie same, jak te, z którymi mieliśmy już do czynienia wielokrotnie. Metoda zwraca ciąg znaków wpisany przez użytkownika. Oto przykład:
import javax.swing.*;
public class input1 {
public static void main(String[] args) {
// wprowadzanie
System.out.println("Chaîne saisie ["+
JOptionPane.showInputDialog(null,"Quel est votre nom","Saisie du nom",JOptionPane.QUESTION_MESSAGE )
+ "]");
}//ręka
}//klasa
Wygląd pola wprowadzania danych:

Wyświetlanie konsoli:
5.4. Okna wyboru
Zajmiemy się teraz kilkoma predefiniowanymi polami wyboru w Javie 2:
JFileChooser | pole wyboru umożliwiające wskazanie pliku w drzewie katalogów |
JColorChooser | pole wyboru umożliwiające wybór koloru |
5.4.1. Okno wyboru JFileChooser
Stworzymy następującą aplikację:

Elementy sterujące są następujące:
Nr | typ | nazwa | rola |
0 | JScrollPane | jScrollPane1 | Przesuwany kontener dla pola tekstowego 1 |
1 | JTextArea sam w JScrollPane | txtTexte | tekst wpisany przez użytkownika lub załadowany z pliku |
2 | JButton | btnSauvegarder | umożliwia zapisanie tekstu z pola 1 w pliku tekstowym |
3 | JButton | btnCharger | umożliwia wczytanie zawartości pliku tekstowego do zmiennej 1 |
4 | JButton | btnEffacer | usuwa zawartość 1 |
Stosowany jest element sterujący niewizualny: jFileChooser1. Jest on pobierany z palety kontenerów Swing z JBuilder:

Umieszczamy komponent w oknie projektowym, ale poza formularzem. Pojawia się on na liście komponentów:

Teraz podajemy kod programu, aby uzyskać ogólny obraz:
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.io.*;
public class dialogues extends JFrame {
// elementy ramki
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();
// filtry plików
javax.swing.filechooser.FileFilter filtreTxt = null;
//Tworzenie ramki
public dialogues() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
// inne inicjalizacje
moreInit();
}
catch(Exception e) {
e.printStackTrace();
}
}
// moreInit
private void moreInit(){
// inicjalizacje podczas tworzenia okna
// filtr *.txt
filtreTxt = new javax.swing.filechooser.FileFilter(){
public boolean accept(File f){
// czy akceptuje się f?
return f.getName().toLowerCase().endsWith(".txt");
}//akceptuj
public String getDescription(){
// opis filtra
return "Fichiers Texte (*.txt)";
}//getDescription
};
// dodajemy filtr
jFileChooser1.addChoosableFileFilter(filtreTxt);
// chcemy również filtr wszystkich plików
jFileChooser1.setAcceptAllFileFilterUsed(true);
// ustawiamy katalog źródłowy skrzynki FileChooser na bieżący katalog
jFileChooser1.setCurrentDirectory(new File("."));
}
//Zainicjuj komponent
private void jbInit() throws Exception {
.......................
}
//Zastąpiono, dzięki czemu możemy zakończyć działanie po zamknięciu okna
protected void processWindowEvent(WindowEvent e) {
......................
}
}
void btnCharger_actionPerformed(ActionEvent e) {
// wybór pliku za pomocą obiektu JFileChooser
// ustawiamy filtr początkowy
jFileChooser1.setFileFilter(filtreTxt);
// wyświetla się okno wyboru
int returnVal = jFileChooser1.showOpenDialog(this);
// czy użytkownik dokonał wyboru?
if(returnVal == JFileChooser.APPROVE_OPTION) {
// umieszczamy plik w polu tekstowym
lireFichier(jFileChooser1.getSelectedFile());
}//if
}//btnCharger_actionPerformed
// lireFichier
private void lireFichier(File fichier){
// wyświetla zawartość pliku tekstowego w polu tekstowym
// czyści pole tekstowe
txtTexte.setText("");
// jakieś dane
BufferedReader IN=null;
String ligne=null;
try{
// otwieranie pliku w trybie odczytu
IN=new BufferedReader(new FileReader(fichier));
// odczyt pliku wiersz po wierszu
while((ligne=IN.readLine())!=null){
txtTexte.append(ligne+"\n");
}//while
// zamknięcie pliku
IN.close();
}catch(Exception ex){
// wystąpił błąd
txtTexte.setText(""+ex);
}//catch
}
// wyczyść
void btnEffacer_actionPerformed(ActionEvent e) {
// kasowanie pola tekstowego
txtTexte.setText("");
}
// zapis
void btnSauvegarder_actionPerformed(ActionEvent e) {
// zapisuje zawartość pola tekstowego do pliku
// ustawia się filtr początkowy
jFileChooser1.setFileFilter(filtreTxt);
// wyświetla okno wyboru opcji zapisywania
int returnVal = jFileChooser1.showSaveDialog(this);
// czy użytkownik dokonał wyboru?
if(returnVal == JFileChooser.APPROVE_OPTION) {
// zapisuje się zawartość pola tekstowego do pliku
écrireFichier(jFileChooser1.getSelectedFile());
}//if
}
// lireFichier
private void écrireFichier(File fichier){
// zapisuje zawartość pola tekstowego do pliku
// jakieś dane
PrintWriter PRN=null;
try{
// otwarcie pliku do zapisu
PRN=new PrintWriter(new FileWriter(fichier));
// zapisuje zawartość pola tekstowego
PRN.print(txtTexte.getText());
// zamykanie pliku
PRN.close();
}catch(Exception ex){
// wystąpił błąd
txtTexte.setText(""+ex);
}//przechwycenie
}
Nie będziemy omawiać kodu metod btnEffacer_Click, lireFichier i écrireFichier, które nie wnoszą nic nowego w stosunku do tego, co już widzieliśmy. Skupimy się na klasie JFileChooser i jej zastosowaniu. Klasa ta jest złożona, można ją określić jako „zbyt skomplikowaną”. W tym miejscu wykorzystujemy jedynie następujące metody:
addChoosableFilter(FileFilter) | ustala typy plików oferowanych do wyboru |
setAcceptAllFileFilterUsed(boolean) | określa, czy typ „Wszystkie pliki” ma być oferowany do wyboru, czy nie |
File getSelectedFile() | plik (File) wybrany przez użytkownika |
int showSaveDialog() | metoda wyświetlająca okno wyboru opcji zapisywania. Zwraca wynik typu int. Wartość jFileChooser.APPROVE_OPTION oznacza, że użytkownik dokonał prawidłowego wyboru. W przeciwnym razie albo anulował wybór, albo wystąpił błąd. |
setCurrentDirectory | w celu ustawienia katalogu początkowego, od którego użytkownik rozpocznie przeglądanie systemu plików |
setFileFilter(FileFilter) | w celu ustawienia aktywnego filtra |
Metoda showSaveDialog wyświetla okno wyboru podobne do poniższego:

1 | lista rozwijana utworzona za pomocą metody addChoosableFilter. Zawiera ona tzw. filtry wyboru reprezentowane przez klasę FileFilter. Zadaniem programisty jest zdefiniowanie tych filtrów i dodanie ich do listy 1. |
2 | bieżący katalog, ustalony przez metodę setCurrentDirectory, jeśli ta metoda została użyta; w przeciwnym razie bieżącym katalogiem będzie folder „Moje dokumenty” w systemie Windows lub katalog domowy w systemie Unix. |
3 | nazwa pliku wybrana lub wpisana bezpośrednio przez użytkownika. Będzie dostępna za pomocą metody getSelectedFile() |
4 | przyciski „Zapisz”/„Anuluj”. Jeśli używany jest przycisk Enregistrer, metoda showSaveDialog zwraca wynik jFileChooser.APPROVE_OPTION |
W jaki sposób tworzone są filtry plików w liście rozwijanej 1? Filtry są dodawane do listy 1 za pomocą metody:
addChoosableFilter(FileFilter) | określa typy plików dostępne do wyboru |
klasy JFileChooser. Pozostaje nam jeszcze zapoznać się z klasą FileFilter. W rzeczywistości jest to klasa javax.swing.filechooser.FileFilter, która jest klasą abstrakcyjną, c.a.d – klasą, której nie można instancjonować, a jedynie od której można tworzyć klasy pochodne. Jest ona zdefiniowana w następujący sposób:
FileFilter() | konstruktor |
boolean accept(File) | wskazuje, czy plik f należy do filtru, czy nie |
String getDescription() | ciąg znaków opisujący filtr |
Weźmy przykład. Chcemy, aby lista rozwijana 1 oferowała filtr umożliwiający wybór plików *.txt z opisem „Pliki tekstowe (*.txt)”.
- musimy utworzyć klasę pochodną od klasy FileFilter
- użyć metody boolean accept(File f), aby zwrócić wartość true, jeśli nazwa pliku f kończy się na .txt
- użyć metody String getDescription(), aby zwrócić opis „Pliki tekstowe (*.txt)”
Filtr ten można zdefiniować w naszej aplikacji w następujący sposób:
javax.swing.filechooser.FileFilter filtreTxt = new javax.swing.filechooser.FileFilter(){
public boolean accept(File f){
// czy akceptujemy f?
return f.getName().toLowerCase().endsWith(".txt");
}//akceptuj
public String getDescription(){
// opis filtra
return "Fichiers Texte (*.txt)";
}//getDescription
};
Ten filtr zostałby dodany do listy filtrów obiektu jFileChooser1 za pomocą instrukcji:
Wszystkie te oraz kilka innych operacji inicjalizacyjnych są wykonywane w metodzie moreInit uruchamianej podczas tworzenia okna (patrz pełny kod programu powyżej). Kod przycisku Sauvegarder jest następujący:
void btnSauvegarder_actionPerformed(ActionEvent e) {
// zapisuje zawartość pola tekstowego do pliku
// ustawia się filtr początkowy
jFileChooser1.setFileFilter(filtreTxt);
// wyświetla okno wyboru opcji zapisywania
int returnVal = jFileChooser1.showSaveDialog(this);
// czy użytkownik dokonał wyboru?
if(returnVal == JFileChooser.APPROVE_OPTION) {
// zapisuje się zawartość pola tekstowego do pliku
écrireFichier(jFileChooser1.getSelectedFile());
}//if
}
Kolejność czynności jest następująca:
- ustawia się aktywny filtr na *.txt, aby umożliwić użytkownikowi wyszukiwanie przede wszystkim tego typu plików. Dostępny jest również filtr „Wszystkie pliki”. Został on dodany w procedurze moreInit. Mamy zatem dwa filtry.
- Wyświetlane jest okno wyboru pliku do zapisania. W tym momencie tracimy kontrolę, ponieważ użytkownik korzysta z tego okna, aby wskazać plik z systemu plików.
- Po opuszczeniu okna wyboru sprawdzana jest wartość zwracana, aby ustalić, czy należy zapisać pole tekstowe. Jeśli tak, należy je zapisać w pliku uzyskanym za pomocą metody getSelectedFile.
Kod związany z przyciskiem „Załaduj” jest bardzo podobny do kodu przycisku „Zapisz”.
void btnCharger_actionPerformed(ActionEvent e) {
// wybór pliku za pomocą obiektu JFileChooser
// ustawiamy filtr początkowy
jFileChooser1.setFileFilter(filtreTxt);
// wyświetlanie okna wyboru
int returnVal = jFileChooser1.showOpenDialog(this);
// czy użytkownik dokonał wyboru?
if(returnVal == JFileChooser.APPROVE_OPTION) {
// umieszczamy plik w polu tekstowym
lireFichier(jFileChooser1.getSelectedFile());
}//if
}//btnCharger_actionPerformed
Istnieją dwie różnice:
- aby wyświetlić okno wyboru plików, stosuje się metodę showOpenDialog zamiast metody showSaveDialog. Wyświetlane okno wyboru jest analogiczne do tego wyświetlanego przez metodę showSaveDialog.
- jeśli użytkownik faktycznie wybrał plik, wywoływana jest metoda lireFichier zamiast metody écrireFichier.
5.4.1.1. Okna wyboru JColorChooser i JFontChooser
Kontynuujemy poprzedni przykład, dodając dwa nowe przyciski:

Nr | typ | nazwa | rola |
6 | JButton | btnCouleur | w celu ustawienia koloru znaków w TextBox |
7 | JButton | btnPolice | w celu ustawienia czcionki dla TextBox |
Komponent JColorChooser, umożliwiający wyświetlenie okna wyboru koloru, można znaleźć na liście komponentów Swing w JBuilder:

Umieszczamy ten komponent w oknie projektowym, ale poza formularzem. Nie jest on widoczny w formularzu, ale mimo to znajduje się na liście komponentów okna:

Klasa JColorChooser jest bardzo prosta. Okno wyboru kolorów wyświetlamy za pomocą metody int showDialog:
static Color | showDialog(Component component, String title, Color initialColor) |
Component component | komponent nadrzędny okna wyboru, zazwyczaj okno JFrame |
String title | tytuł wyświetlany w pasku tytułu okna wyboru |
Kolor intialColor | kolor pierwotnie wybrany w polu wyboru |
Jeśli użytkownik wybierze kolor, metoda zwraca ten kolor, w przeciwnym razie zwraca wartość null. Kod powiązany z przyciskiem Couleur jest następujący:
void btnCouleur_actionPerformed(ActionEvent e) {
// wybór koloru tekstu za pomocą komponentu JColorChooser
Color couleur;
if((couleur=jColorChooser1.showDialog(this,"Choix d'une couleur",Color.BLACK))!=null){
// ustawianie koloru znaków w polu tekstowym
txtTexte.setForeground(couleur);
}//if
}
Klasa Color jest zdefiniowana w klasie java.awt.Color. Zdefiniowano w niej różne stałe, w tym Color.BLACK dla koloru czarnego. Wyświetlane okno wyboru wygląda następująco

Co dość zaskakujące, biblioteka Swing nie oferuje klasy służącej do wyboru czcionki. Na szczęście w Internecie dostępne są zasoby Java. Wyszukując słowo kluczowe „JFontChooser”, które wydaje się być potencjalną nazwą takiej klasy, można znaleźć kilka wyników. Poniższy przykład pozwoli nam skonfigurować klasę JBuilder tak, aby korzystała z pakietów nieprzewidzianych w jej pierwotnej konfiguracji.
Pobrany pakiet nosi nazwę swingextras.jar i został umieszczony w folderze <jdk>\jre\lib\perso, gdzie <jdk> oznacza katalog instalacyjny JDK używanego przez JBuilder. Mógł on zostać umieszczony w dowolnym innym miejscu.
![]() | ![]() |
Przyjrzyjmy się zawartości pakietu SwingExtras.jar:

Znajduje się tam kod źródłowy Java komponentów zawartych w pakiecie. Znajdują się tam również same klasy:

Z tego archiwum warto zapamiętać, że klasa JFontChooser w rzeczywistości nazywa się com.lamatek.swingextras.JFontChooser. Jeśli nie chcemy wpisywać pełnej nazwy, na początku programu musimy napisać:
W jaki sposób kompilator i maszyna wirtualna Java odnajdą ten nowy pakiet? W przypadku bezpośredniego użycia klasy JDK zostało to już wyjaśnione, a czytelnik może znaleźć wyjaśnienia w akapicie poświęconym pakietom Java. Poniżej szczegółowo opisujemy metodę, którą należy zastosować w przypadku klasy JBuilder. Pakiety konfiguruje się w menu Opcje/Konfiguruj JDK:

1 | Przycisk Modifier (1) pozwala wskazać programowi JBuilder, który pakiet JDK ma być używany. W tym przykładzie JBuilder przyniósł ze sobą JDK w wersji 1.3.1. Kiedy pojawiła się wersja JDK 1.4, została ona zainstalowana oddzielnie od JBuilder, a przycisk Modifier posłużył do poinformowania JBuilder, abykorzystał odtąd z JDK 1.4, wskazując katalog instalacyjny tego ostatniego |
2 | katalogu głównego JDK, z którego obecnie korzysta JBuilder |
3 | lista archiwów Java (.jar) używanych przez JBuilder. Można dodać kolejne, korzystając z przycisku Ajouter (4) |
4 | Przycisk Ajouter (4) pozwala na dodanie nowych pakietów, z których JBuilder będzie korzystać zarówno podczas kompilacji, jak i wykonywania programów. Wykorzystano go tutaj do dodania pakietu SwingExtras.jar (5) |
Teraz JBuilder jest poprawnie skonfigurowany, aby móc korzystać z klasy JFontChooser. Jednak aby móc z niej prawidłowo korzystać, potrzebowalibyśmy dostępu do definicji tej klasy. Archiwum swingextras.jar zawiera pliki HTML, które można by wyodrębnić w celu ich wykorzystania. Nie ma takiej potrzeby. Dokumentacja Java zawarta w plikach .jar jest bezpośrednio dostępna z poziomu JBuilder. W tym celu należy skonfigurować powyższą zakładkę Documentation (6). Pojawi się następujące nowe okno:

Przycisk Ajouter pozwala nam wskazać, że plik SwingExtras.jar ma zostać przeszukany pod kątem dokumentacji. Po zatwierdzeniu tej czynności można zauważyć, że faktycznie mamy dostęp do dokumentacji pliku SwingExtras.jar. Przekłada się to na różne udogodnienia:
- jeśli zaczniemy wpisywać instrukcję importu
można zauważyć, że plik JBuilder udostępnia nam pomoc:

Pakiet com.lamatek został pomyślnie znaleziony.
- Jeśli teraz przejdziemy do następującego programu:
Po wpisaniu kodu F1 dla słowa kluczowego JFontChooser otrzymujemy pomoc dotyczącą tej klasy:

W pasku stanu 1 widać, że faktycznie wykorzystywany jest plik HTML z pakietu swingextras.jar. Powyższy przykład jest na tyle jasny, że możemy napisać kod przycisku Police w naszej aplikacji:
void btnPolice_actionPerformed(ActionEvent e) {
// wybór czcionki tekstu za pomocą komponentu JFontChooser
jFontChooser1 = new JFontChooser(new Font("Arial", Font.BOLD, 12));
if (jFontChooser1.showDialog(this, "Choix d'une police") == JFontChooser.ACCEPT_OPTION) {
// zmiana czcionki znaków w polu tekstowym
txtTexte.setFont(jFontChooser1.getSelectedFont());
}//if
}
Okno wyboru wyświetlane przez powyższą metodę showDialog wygląda następująco:

5.5. Aplikacja graficzna IMPOTS
Wracamy do aplikacji IMPOTS, którą omówiliśmy już dwukrotnie. Dodajemy do niej teraz interfejs graficzny:

Elementy sterujące są następujące
nr | typ | nazwa | rola |
1 | JRadioButton | rdOui | zaznaczyć, jeśli jest w związku małżeńskim |
2 | JRadioButton | rdNon | zaznaczyć, jeśli nie jest żonaty/zamężna |
3 | JSpinner | spinEnfants | liczba dzieci podatnika Minimum=0, Maksimum=20, Przyrost=1 |
4 | JTextField | txtSalaire | roczne wynagrodzenie podatnika w F |
5 | JLabel | lblImpots | kwota podatku do zapłaty |
6 | JTextField | txtStatus | pole komunikatów o stanie – nie można edytować |
Menu wygląda następująco:
opcja główna | opcja podrzędna | nazwa | rola |
Podatki | |||
Inicjalizacja | mnuInitialiser | ładuje dane niezbędne do obliczeń z pliku tekstowego | |
Oblicz | mnuCalculer | oblicza podatek do zapłaty, gdy wszystkie niezbędne dane są dostępne i poprawne | |
Usuń | mnuEffacer | przywraca formularz do stanu początkowego | |
Wyjdź | mnuQuitter | zamyka aplikację |
Zasady działania
- menu Calculer pozostaje wyłączone, dopóki w polu wynagrodzenia nie ma żadnych danych
- jeśli po uruchomieniu obliczeń okaże się, że wynagrodzenie jest nieprawidłowe, zgłaszany jest błąd:

Poniżej przedstawiono program. Wykorzystuje on klasę impots utworzoną w rozdziale poświęconym klasom. Część kodu wygenerowanego automatycznie przez JBuilder nie została tutaj zamieszczona.
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 {
// komponenty okna
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;
// atrybuty klasy
double[] limites=null;
double[] coeffr=null;
double[] coeffn=null;
impots objImpots=null;
//Tworzenie ramki
public frmImpots() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
// inne inicjalizacje
moreInit();
}
// inicjalizacja formularza
private void moreInit(){
// menu „Oblicz” zablokowane
mnuCalculer.setEnabled(false);
// pola wprowadzania danych zablokowane
txtSalaire.setEditable(false);
txtSalaire.setBackground(Color.WHITE);
// pole stanu
txtStatus.setBackground(Color.WHITE);
// pokrętło „Liczba dzieci” – od 0 do 20 dzieci
spinEnfants=new JSpinner(new SpinnerNumberModel(0,0,20,1));
spinEnfants.setBounds(new Rectangle(137,60,40,27));
contentPane.add(spinEnfants);
// filtr *.txt dla listy rozwijanej
filtreTxt = new javax.swing.filechooser.FileFilter(){
public boolean accept(File f){
// czy akceptuje się literę „f”?
return f.getName().toLowerCase().endsWith(".txt");
}//akceptuj
public String getDescription(){
// opis filtra
return "Fichiers Texte (*.txt)";
}//getDescription
};
// dodajemy filtr *.txt
jFileChooser1.addChoosableFileFilter(filtreTxt);
// chcemy również filtr wszystkich plików
jFileChooser1.setAcceptAllFileFilterUsed(true);
// ustawiamy katalog źródłowy skrzynki FileChooser
jFileChooser1.setCurrentDirectory(new File("."));
}//moreInit
//Zainicjuj komponent
private void jbInit() throws Exception {
................
}
//Zastąpiono, dzięki czemu możemy zakończyć działanie po zamknięciu okna
protected void processWindowEvent(WindowEvent e) {
.....................
}
void mnuQuitter_actionPerformed(ActionEvent e) {
// kończymy działanie aplikacji
System.exit(0);
}
void mnuInitialiser_actionPerformed(ActionEvent e) {
// ładujemy plik danych
// wybrany za pomocą okna wyboru JFileChooser1
jFileChooser1.setFileFilter(filtreTxt);
if (jFileChooser1.showOpenDialog(this)!=JFileChooser.APPROVE_OPTION)
return;
// przetwarzamy wybrany plik
try{
// odczyt danych
lireFichier(jFileChooser1.getSelectedFile());
// utworzenie obiektu podatkowego
objImpots=new impots(limites,coeffr,coeffn);
// potwierdzenie
txtStatus.setText("Données chargées");
// wynagrodzenie można zmienić
txtSalaire.setEditable(true);
// nie można już wprowadzać zmian
mnuInitialiser.setEnabled(false);
}catch(Exception ex){
// problem
txtStatus.setText("Erreur : " + ex.getMessage());
// koniec
return;
}//przechwycenie
}
private void lireFichier(File fichier) throws Exception {
// tabele danych
ArrayList aLimites=new ArrayList();
ArrayList aCoeffR=new ArrayList();
ArrayList aCoeffN=new ArrayList();
String[] champs=null;
// otwarcie pliku do odczytu
BufferedReader IN=new BufferedReader(new FileReader(fichier));
// plik jest odczytywany wiersz po wierszu
// mają postać: limit coeffr coeffn
String ligne=null;
int numLigne=0; // numer bieżącej linii
while((ligne=IN.readLine())!=null){
// kolejny wiersz
numLigne++;
// rozbijamy wiersz na pola
champs=ligne.split("\\s+");
// 3 pola?
if(champs.length!=3)
throw new Exception("ligne " + numLigne + "erronée dans fichier des données");
// pobieramy trzy pola
aLimites.add(champs[0]);
aCoeffR.add(champs[1]);
aCoeffN.add(champs[2]);
}//while
// zamknięcie pliku
IN.close();
// przeniesienie danych do tablic o określonych granicach
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) {
// obliczenie podatku
// weryfikacja wynagrodzenia
int salaire=0;
try{
salaire=Integer.parseInt(txtSalaire.getText().trim());
if(salaire<0) throw new Exception();
}catch (Exception ex){
// komunikat o błędzie
txtStatus.setText("Salaire incorrect. Recommencez");
// fokus na polu z błędem
txtSalaire.requestFocus();
// powrót do interfejsu
return;
}
// liczba dzieci
Integer InbEnfants=(Integer)spinEnfants.getValue();
// obliczenie podatku
lblImpots.setText(""+objImpots.calculer(rdOui.isSelected(),InbEnfants.intValue(),salaire));
// usunięcie komunikatu o stanie
txtStatus.setText("");
}
void txtSalaire_caretUpdate(CaretEvent e) {
// zmieniło się wynagrodzenie – aktualizujemy menu „Oblicz”
mnuCalculer.setEnabled(! txtSalaire.getText().trim().equals(""));
}
void mnuEffacer_actionPerformed(ActionEvent e) {
// wyczyść formularz
rdNon.setSelected(true);
spinEnfants.getModel().setValue(new Integer(0));
txtSalaire.setText("");
mnuCalculer.setEnabled(false);
lblImpots.setText("");
}
}
W tym przypadku wykorzystaliśmy komponent dostępny dopiero od wersji JDK 1.4, a mianowicie JSpinner. Jest to licznik, który w tym przypadku pozwala użytkownikowi ustawić liczbę elementów podrzędnych. Ten komponent Swing nie był dostępny na pasku komponentów Swing w wersji JBuilder 6 użytej do testów. Nie uniemożliwia to jednak jego użycia, choć procedura jest nieco bardziej skomplikowana niż w przypadku komponentów dostępnych na pasku komponentów. W rzeczywistości nie można umieścić komponentu JSpinner na formularzu podczas projektowania. Należy to zrobić w czasie wykonywania. Przyjrzyjmy się kodowi, który to realizuje:
// przewijacz „Dzieci” – wprowadź liczbę od 0 do 20 dzieci
spinEnfants=new JSpinner(new SpinnerNumberModel(0,0,20,1));
spinEnfants.setBounds(new Rectangle(137,60,40,27));
contentPane.add(spinEnfants);
Pierwszy wiersz tworzy komponent JSpinner. Komponent ten może służyć do różnych celów, nie tylko jako inkrementator liczb całkowitych, jak w tym przypadku. Argumentem konstruktora JSpinner jest tutaj szablon inkrementatora liczb przyjmujący cztery parametry (wartość, min, max, przyrost). Komponent ma następującą postać:
![]()
valeur | wartość początkowa wyświetlana w komponencie |
min | minimalna wartość, jaką można wyświetlić w komponencie |
max | maksymalna wartość, jaką można wyświetlić w komponencie |
incrément | wartość przyrostu wyświetlanej wartości przy użyciu strzałek w górę/w dół w komponencie |
Wartość komponentu uzyskuje się za pomocą jego metody getValue, która zwraca typ Object. Stąd konieczność kilku konwersji typów, aby uzyskać potrzebną liczbę całkowitą:
// liczba dzieci
Integer InbEnfants=(Integer)spinEnfants.getValue();
// obliczenie podatku
lblImpots.setText(""+objImpots.calculer(rdOui.isSelected(),
InbEnfants.intValue(),salaire));
Po zdefiniowaniu komponentu JSpinner jest on umieszczany w oknie:
Przede wszystkim użytkownik musi skorzystać z opcji menu Initialiser, która tworzy obiekt impots za pomocą konstruktora
klasy impots. Przypominamy, że klasa ta została zdefiniowana jako przykład w rozdziale poświęconym klasom. W razie potrzeby należy się do niego odwołać. Trzy tablice wymagane przez konstruktor są wypełniane na podstawie zawartości pliku tekstowego o następującej postaci:
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 |
Każdy wiersz zawiera trzy liczby oddzielone co najmniej jedną spacją. Ten plik tekstowy jest wybierany przez użytkownika za pomocą komponentu JFileChooser. Po utworzeniu obiektu typu impots pozostaje jedynie poprosić użytkownika o podanie trzech potrzebnych informacji: czy jest żonaty/zamężna, liczba dzieci, roczne wynagrodzenie, a następnie wywołać metodę calculer klasy impots. Operację tę można powtórzyć wielokrotnie. Obiekt typu impots jest tworzony tylko raz, podczas korzystania z opcji Initialiser.
5.6. Tworzenie apletów
5.6.1. Wprowadzenie
Po napisaniu aplikacji z interfejsem graficznym dość łatwo jest przekształcić ją w applet. Aplikacja ta, przechowywana na komputerze A, może zostać pobrana za pomocą przeglądarki internetowej z komputera B podłączonego do Internetu. W ten sposób pierwotna aplikacja jest udostępniana wielu użytkownikom i właśnie w tym polega główna zaleta przekształcania aplikacji w aplet. Niemniej jednak nie każdą aplikację można w ten sposób przekształcić: aby nie utrudniać pracy użytkownikowi korzystającemu z apletu w przeglądarce, środowisko apletu podlega pewnym ograniczeniom:
- aplet nie może odczytywać ani zapisywać danych na dysku użytkownika
- może komunikować się wyłącznie z komputerem, z którego została pobrana przez przeglądarkę.
Są to poważne ograniczenia. Oznacza to na przykład, że aplikacja, która musi odczytać informacje z pliku lub bazy danych, będzie musiała zwrócić się o nie do aplikacji pośredniczącej znajdującej się na serwerze, z którego została pobrana.
Ogólna struktura prostej aplikacji internetowej wygląda następująco:

- klient żąda dokumentu HTML od serwera internetowego, zazwyczaj za pomocą przeglądarki. Dokument ten może zawierać aplet, który będzie działał jako samodzielna aplikacja graficzna w ramach dokumentu HTML wyświetlanego przez przeglądarkę klienta.
- Aplet ten będzie miał dostęp do danych, ale wyłącznie do tych znajdujących się na serwerze internetowym. Nie będzie miał dostępu ani do zasobów komputera klienckiego, na którym jest uruchomiony, ani do zasobów innych komputerów w sieci, poza tym, z którego został pobrany.
5.6.2. Klasa JApplet
5.6.2.1. Définition
Aplikacja może zostać pobrana przez przeglądarkę internetową, jeśli jest instancją klasy java.applet.Applet lub klasy javax.swing.JApplet. Ta ostatnia wywodzi się z pierwszej, która z kolei wywodzi się z klasy Panel, a ta z kolei wywodzi się z klasy Container. Instancja klasy Applet lub JApplet, będąca typu container, może zatem zawierać komponenty (Component), takie jak przyciski, pola wyboru, listy itp. Przedstawmy kilka wskazówek dotyczących roli poszczególnych metod:
Metoda | Rola |
public void destroy(); | niszczy instancję apletu |
public AppletContext getAppletContext(); | pobiera kontekst wykonania apletu (dokument HTML, w którym się znajduje, inne aplety z tego samego dokumentu itp.) |
public String getAppletInfo(); | zwraca ciąg znaków zawierający informacje o aplecie |
public AudioClip getAudioClip(URL url); | ładuje plik audio określony przez URL |
public AudioClip getAudioClip(URL url, String name); | ładuje plik audio określony przez URL/name |
public URL getCodeBase(); | zwraca obiekt URL apletu |
public URL getDocumentBase(); | zwraca URL z dokumentu HTML zawierającego aplet |
public Image getImage(URL url); | pobiera obraz określony przez URL |
public Image getImage(URL url, String name); | pobiera obraz określony przez URL/name |
public String getParameter(String name); | pobiera wartość parametru name zawartego w tagu <applet> dokumentu HTML, który zawiera aplet. |
public void init(); | ta metoda jest wywoływana przez przeglądarkę podczas pierwszego uruchomienia apletu |
public boolean isActive(); | stan apletu |
public void play(URL url); | odtwarza plik dźwiękowy określony przez URL |
public void play(URL url, String name); | odtwarza plik dźwiękowy określony przez UR/name |
public void resize(Dimension d); | ustawia wymiary ramki apletu |
public void resize(int width, int height); | to samo |
public final void setStub(AppletStub stub); | |
public void showStatus(String msg); | wyświetla komunikat na pasku stanu apletu |
public void start(); | ta metoda jest wywoływana przez przeglądarkę przy każdym wyświetleniu dokumentu zawierającego aplet |
public void stop(); | ta metoda jest wywoływana przez przeglądarkę za każdym razem, gdy dokument zawierający aplet jest porzucany na rzecz innego (zmiana URL przez użytkownika) |
Klasa JApplet wprowadziła kilka ulepszeń do klasy Applet, w szczególności możliwość zawierania komponentów JMenuBar i c.a.d. w menu, co nie było możliwe w przypadku klasy Applet.
5.6.2.2. Uruchamianie apletu: metody init, start i stop
Gdy przeglądarka ładuje aplet, wywołuje trzy jego metody:
init | Metoda ta jest wywoływana podczas pierwszego załadowania apletu. Należy w niej umieścić inicjalizacje niezbędne dla działania aplikacji. |
start | Ta metoda jest wywoływana za każdym razem, gdy dokument zawierający aplet staje się bieżącym dokumentem przeglądarki. Tak więc, gdy użytkownik ładuje aplet, metody init i start zostaną wykonane w tej kolejności. Gdy użytkownik opuści ten dokument, aby wyświetlić inny, zostanie wykonana metoda stop. Gdy później powróci do tego dokumentu, zostanie wykonana metoda start. |
stop | Ta metoda jest wywoływana za każdym razem, gdy użytkownik opuszcza dokument zawierający aplet. |
W przypadku wielu apletów wystarczy tylko metoda init. Metody start** i stop są potrzebne tylko wtedy, gdy aplikacja uruchamia zadania (wątki), które działają równolegle i nieprzerwanie, często bez wiedzy użytkownika. Gdy użytkownik opuszcza dokument, widoczna część aplikacji znika, ale te zadania działające w tle nadal pracują. Często jest to zbędne. W takiej sytuacji wykorzystuje się wywołanie metody **stop przez przeglądarkę, aby je zatrzymać. Jeśli użytkownik powróci do dokumentu, wykorzystuje się wywołanie metody **start** przez przeglądarkę, aby je ponownie uruchomić.
Weźmy na przykład aplet, który posiada zegar w swoim interfejsie graficznym. Jest on obsługiwany przez zadanie w tle (wątek). Gdy użytkownik opuszcza stronę apletu w przeglądarce, nie ma sensu utrzymywać zegara, który stał się niewidoczny: w metodzie stop** apletu zatrzymamy wątek obsługujący zegar. W metodzie start** uruchomimy go ponownie, aby gdy użytkownik powróci na stronę apletu, zastał zegar wskazujący aktualny czas.
5.6.3. Przekształcenie aplikacji graficznej w aplet
Zakładamy tutaj, że taka transformacja jest możliwa, to znaczy że spełnia ona ograniczenia dotyczące działania apletów. Aplikacja jest uruchamiana za pomocą metody main jednej z jej klas:
Taka aplikacja jest przekształcana w aplet w następujący sposób:
import java.applet.JApplet;
…
public class application extends JApplet{
…
public void init(){
…
}
…
}// koniec klasy
Należy zwrócić uwagę na następujące kwestie:
- klasa application wywodzi się teraz z klasy JApplet
- metoda main została zastąpiona metodą init.
Jako przykład powrócimy do analizowanej wcześniej aplikacji: zarządzania listami.

Elementy tego okna są następujące:
nr | typ | nazwa | rola |
1 | JTextField | txtSaisie | pole wprowadzania danych |
2 | JList | jList1 | lista zawarta w kontenerze jScrollPane1 |
3 | JList | jList2 | lista zawarta w kontenerze jScrollPane2 |
4 | JButton | cmd1To2 | przenosi zaznaczone elementy z listy 1 do listy 2 |
5 | JButton | cmd2To1 | wykonuje operację odwrotną |
6 | JButton | cmdRaz1 | wyczyść listę 1 |
7 | JButton | cmdRaz2 | wyczyść listę 2 |
Struktura aplikacji wyglądała następująco:
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();
/**Utwórz tabelę*/
public interfaceAppli() {
enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}//interfaceAppli
/**Zainicjowanie komponentu*/
private void jbInit() throws Exception {
...
txtSaisie.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(ActionEvent e) {
txtSaisie_actionPerformed(e);
}
});
...
// Jlist1 jest umieszczony w kontenerze jScrollPane1
jScrollPane1.getViewport().add(jList1, null);
// Jlist2 jest umieszczony w kontenerze jScrollPane2
jScrollPane2.getViewport().add(jList2, null);
...
}
/**Zastąpiono, dzięki czemu możemy zakończyć działanie po zamknięciu okna*/
protected void processWindowEvent(WindowEvent e) {
...
}
void txtSaisie_actionPerformed(ActionEvent e) {
.............
}//klasa
void cmdRaz1_actionPerformed(ActionEvent e) {
// wyczyść listę 1
v1.removeAllElements();
}//polecenie Raz1
void cmdRaz2_actionPerformed(ActionEvent e) {
// wyczyść listę 2
v2.removeAllElements();
}///polecenie Raz2
Aby przekształcić klasę appli w applet, należy postępować w następujący sposób:
- zmodyfikować poprzednią klasę interfaceAppli tak, aby nie wywodziła się już z klasy JFrame, lecz z klasy JApplet:
- usunąć instrukcję ustalającą tytuł okna JFrame. Aplet JApplet nie posiada paska tytułu
- zmienić konstruktor na metodę init i w tej metodzie usunąć obsługę zdarzeń okna (WindowListener, ...). Aplet jest kontenerem, którego rozmiaru nie można zmieniać ani zamknąć.
/**Utwórz ramkę*/
public init() {
// enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}//interfaceAppli
- Metodę processWindowEvent należy usunąć lub skomentować
/**Zastąpiono, dzięki czemu możemy wyjść, gdy okno jest zamknięte*/
//protected void processWindowEvent(WindowEvent e) {
// super.processWindowEvent(e);
// if (e.getID() == WindowEvent.WINDOW_CLOSING) {
// System.exit(0);
// }
// }
Jako przykład podajemy pełny kod apletu, z wyjątkiem części wygenerowanej automatycznie przez 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();
/**Tworzenie ramki*/
public void init() {
// enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
}//interfaceAppli
/**Zainicjuj komponent*/
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) {
// tekst wprowadzony został zatwierdzony
// odzyskujemy go po usunięciu spacji na początku i na końcu
String texte=txtSaisie.getText().trim();
// jeśli jest pusty, nie jest nam potrzebny
if(texte.equals("")){
// komunikat o błędzie
JOptionPane.showMessageDialog(this,"Vous devez taper un texte",
"Erreur",JOptionPane.WARNING_MESSAGE);
// koniec
return;
}//if
// jeśli nie jest puste, dodajemy je do wartości z listy 1
v1.addElement(texte);
// i czyścimy pole wprowadzania danych
txtSaisie.setText("");
}
void cmd1To2_actionPerformed(ActionEvent e) {
// przeniesienie wybranych elementów z listy 1 do listy 2
transfert(jList1,jList2);
}//cmd1To2
private void transfert(JList L1, JList L2){
// przeniesienie wybranych elementów z listy 1 do listy 2
// pobieramy tablicę indeksów elementów wybranych w L1
int[] indices=L1.getSelectedIndices();
// co należy zrobić?
if (indices.length==0) return;
// pobieramy wartości z L1
DefaultListModel v1=(DefaultListModel)L1.getModel();
// oraz z L2
DefaultListModel v2=(DefaultListModel)L2.getModel();
for(int i=indices.length-1;i>=0;i--){
// do L2 dodajemy wartości wybrane z L1
v2.addElement(v1.elementAt(indices[i]));
// elementy z L1 skopiowane do L2 muszą zostać usunięte z L1
v1.removeElementAt(indices[i]);
}//dla
}//przeniesienie
private void affiche(String message){
// wyświetla komunikat
JOptionPane.showMessageDialog(this,message,
"Suivi",JOptionPane.INFORMATION_MESSAGE);
}// wyświetla
void cmd2To1_actionPerformed(ActionEvent e) {
// przeniesienie wybranych elementów z jList2 do jList1
transfert(jList2,jList1);
}//cmd2TO1
void cmdRaz1_actionPerformed(ActionEvent e) {
// wyczyść listę 1
v1.removeAllElements();
}//polecenie Raz1
void cmdRaz2_actionPerformed(ActionEvent e) {
// pusta lista 2
v2.removeAllElements();
}//polecenie Raz2
}//klasa
Można skompilować kod źródłowy tego apletu. Robimy to tutaj przy użyciu pliku JDK, bez pliku 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
Aplikację można przetestować za pomocą programu AppletViewer z pakietu JDK, który umożliwia uruchamianie apletów lub przeglądarki. W tym celu należy utworzyć dokument o nazwie HTML appli.htm, który będzie zawierał aplet:
<html>
<head>
<title>listes swing</title>
</head>
<body>
<applet
code="interfaceAppli.class"
width="400"
height="300">
</applet>
</body>
</html>
Mamy tu do czynienia z klasycznym dokumentem HTML, z wyjątkiem obecności tagu applet. Został on użyty z trzema parametrami:
code="interfaceAppli.class" | nazwa skompilowanej klasy JAVA, która ma zostać załadowana w celu uruchomienia apletu |
width="400" | szerokość ramki apletu w dokumencie |
height="300" | wysokość ramki apletu w dokumencie |
Po zapisaniu pliku appli.htm można go załadować za pomocą programu appletviewer z pakietu JDK lub za pomocą przeglądarki. W oknie DOS, w folderze zawierającym plik appli.htm, należy wpisać następujące polecenie:
appletviewer appli.htm
Zakładamy tutaj, że katalog pliku wykonywalnego appletviewer.exe znajduje się w katalogu PATH okna DOS; w przeciwnym razie należałoby podać pełną ścieżkę do pliku wykonywalnego appletviewer.exe. Pojawi się następujące okno:

Zatrzymujemy działanie apletu za pomocą opcji Applet/Quitter. Teraz przetestujmy aplet w przeglądarce. Przeglądarka musi korzystać z maszyny wirtualnej Java 2, aby móc wyświetlać komponenty Swing. Jeszcze do niedawna (2001 r.) to ograniczenie stanowiło problem, ponieważ firma Sun wydawała pliki JDK, a producenci przeglądarek dostosowywali się do nich z dużym opóźnieniem. Ostatecznie firma Sun wyeliminowała tę przeszkodę, udostępniając użytkownikom aplikację o nazwie „Java plugin”, która umożliwia przeglądarkom Internet Explorer i Netscape Navigator korzystanie z najnowszych wersji JRE wydanych przez firmę Sun (JRE = Java Runtime Environment). Poniższe testy przeprowadzono przy użyciu IE 5.5 z wtyczką Java 1.4.
Pierwszym sposobem przetestowania apletu interfaceAppli.class jest załadowanie pliku HTML appli.htm bezpośrednio w przeglądarce poprzez dwukrotne kliknięcie na niego. Przeglądarka wyświetli wówczas stronę HTML wraz z apletem bez konieczności korzystania z serwera WWW:

Na podstawie pliku URL (1) widać, że plik został załadowany bezpośrednio do przeglądarki. W poniższym przykładzie plik appli.htm został pobrany z serwera WWW Apache działającego na porcie 81 na komputerze lokalnym:

5.6.4. Opcja formatowania <applet> w dokumencie HTML
Zauważyliśmy, że w dokumencie HTML aplet był odwołany za pomocą tagu formatującego <applet>. Tag ten może mieć różne parametry:
<applet
code=
width=
height=
codebase=
align=
hspace=
vspace=
alt=
>
<param name1=nom1 value=val1>
<param name2=nom2 value=val2>
texte
>
</applet>
Znaczenie parametrów jest następujące:
Parametr | Znaczenie |
code | obowiązkowy – nazwa pliku .class do wykonania |
width | obowiązkowe – szerokość apletu w dokumencie |
height | obowiązkowe – wysokość … |
codebase | opcjonalne – ścieżka do katalogu zawierającego aplet, który ma zostać uruchomiony. Jeśli nie podano ścieżki, aplet zostanie wyszukany w katalogu dokumentu HTML, który do niego odwołuje się |
align | opcjonalne – pozycjonowanie (LEFT, RiGHT, CENTER) apletu w dokumencie |
hspace | opcjonalnie – poziomy margines otaczający aplet, wyrażony w pikselach |
vspace | opcjonalne – pionowy margines otaczający aplet, wyrażony w pikselach |
alt | opcjonalnie – tekst wyświetlany zamiast apletu, jeśli przeglądarka nie może go załadować |
param | opcjonalny – parametr przekazywany do apletu, określający jego nazwę (name) i wartość (value). Aplet będzie mógł pobrać wartość parametru „nazwa1” za pomocą val1=getParameter("nazwa1") Można użyć dowolnej liczby parametrów |
texte | opcjonalne – zostanie wyświetlone przez każdą przeglądarkę, która nie jest w stanie uruchomić apletu, na przykład dlatego, że nie posiada wirtualnej maszyny Java. |
Weźmy przykład ilustrujący przekazywanie parametrów do apletu:
<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>
Kod Java apletu interfaceParams został wygenerowany zgodnie z powyższymi wskazówkami. Stworzono aplikację JBuilder, a następnie wprowadzono kilka zmian wymienionych powyżej:
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);
//Utwórz ramkę
public void init() {
// enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
// inne inicjalizacje
moreInit();
}
// inicjalizacje
public void moreInit(){
// wyświetla wartości parametrów apletu
params.addElement("nom=param1 valeur="+getParameter("param1"));
params.addElement("nom=param2 valeur="+getParameter("param2"));
}//więcej inicjalizacji
//Zainicjuj komponent
private void jbInit() throws Exception {
............
this.setSize(new Dimension(205, 156));
//this.setTitle („Parametry apletu”);
jScrollPane1.setBounds(new Rectangle(19, 53, 160, 73));
............
}
}
Wynik działania z AppletViewer:

5.6.5. Dostęp do zasobów zdalnych z poziomu apletu
Wiele aplikacji musi korzystać z informacji zawartych w plikach lub bazach danych. Wspomnieliśmy już, że aplet nie ma dostępu do zasobów komputera, na którym jest uruchamiany. Jest to środek wynikający ze zdrowego rozsądku. W przeciwnym razie wystarczyłoby napisać aplet, który „szpiegowałby” dysk użytkowników, którzy go uruchamiają. Aplet ma jednak dostęp do zasobów serwera, z którego został pobrany, na przykład do plików. Temu właśnie przyjrzymy się teraz.
5.6.5.1. Klasa URL
Każda aplikacja Java może odczytać plik znajdujący się na komputerze w sieci dzięki klasie java.net.URL (URL = Uniform Resource Locator). URL identyfikuje zasób sieciowy, komputer, na którym się znajduje, a także protokół i port komunikacyjny, które należy wykorzystać do jego pobrania, w postaci:
protokół:port//komputer/plik
Tak więc adres URL http://www.ibm.com/index.html wskazuje plik index.html znajdujący się na komputerze www.ibm.com. Dostęp do niego odbywa się za pośrednictwem protokołu http. Port nie jest określony: przeglądarka użyje portu 80, który jest domyślnym portem usługi HTTP.
Przyjrzyjmy się bliżej niektórym elementom klasy URL:
public URL(String spec) | tworzy instancję klasy URL na podstawie ciągu znaków o formacie „protokół:port//komputer/plik” – zgłasza wyjątek, jeśli składnia ciągu nie odpowiada formatowi URL |
public String getFile() | pozwala uzyskać pole „plik” z ciągu znaków „protokół:port//komputer/plik” obiektu typu URL |
public String getHost() | pozwala uzyskać pole „machine” z ciągu znaków „protokół:port//maszyna/plik” z URL |
public String getPort() | pozwala uzyskać pole „port” z ciągu znaków „protokół:port//komputer/plik” z URL |
public String getProtocol() | pozwala uzyskać pole protokołu z ciągu znaków „protokół:port//komputer/plik” z URL |
public URLConnection openConnection() | otwiera połączenie ze zdalnym komputerem getHost() na jego porcie getPort() zgodnie z protokołem getProtocol() w celu odczytania pliku getFile(). Rzuca wyjątek, jeśli nie udało się nawiązać połączenia |
public final InputStream openStream() | skrót dla openConnection().getInputStream(). Pozwala uzyskać strumień wejściowy, z którego będzie można odczytać zawartość pliku getFile(). Rzuca wyjątek, jeśli nie udało się uzyskać strumienia |
public String toString() | wyświetla identyfikator instancji klasy URL |
Są tu dwie metody, które nas interesują:
- public URL(String spec) – służy do określenia pliku, który ma zostać przetworzony
- public final InputStream openStream() do przetworzenia pliku
5.6.5.2. Przykład programu konsolowego
Napiszemy program w języku Java, bez interfejsu graficznego, którego zadaniem będzie wyświetlenie na ekranie zawartości pliku URL przekazanego mu jako parametr. Przykładowe wywołanie mogłoby wyglądać następująco:
Program jest stosunkowo prosty:
import java.net.*; // dla klasy URL
import java.io.*; // dla strumieni (stream)
public class urlcontenu{
// wyświetla zawartość URL przekazaną jako argument
// treść ta musi być tekstem, aby była czytelna
public static void main (String arg[]){
// sprawdzanie argumentów
if(arg.length==0){
System.err.println("Syntaxe pg url");
System.exit(0);
}
try{
// tworzenie obiektu URL
URL url=new URL(arg[0]);
// odczyt treści
try{
// tworzenie strumienia wejściowego
BufferedReader is=new BufferedReader(new InputStreamReader(url.openStream()));
try{
// odczyt wierszy tekstu ze strumienia wejściowego
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);
}
}// koniec funkcji main
}// koniec klasy
Po sprawdzeniu, czy argument rzeczywiście istnieje, próbujemy utworzyć obiekt typu URL przy użyciu tego argumentu:
// utworzenie URL
URL url=new URL(arg[0]);
Tworzenie to może się nie powieść, jeśli argument nie jest zgodny ze składnią URL protocole:port//machine/fichier. Jeśli mamy składniowo poprawny plik URL, próbujemy utworzyć strumień wejściowy, z którego będzie można odczytywać wiersze tekstu. Strumień wejściowy dostarczany przez funkcję URL URL.openStream() zapewnia strumień typu InputStream, który jest strumieniem zorientowanym na znaki: odczyt odbywa się znak po znaku i należy samodzielnie tworzyć wiersze. Aby móc odczytywać wiersze tekstu, należy użyć metody readLine z klas BufferedReader lub DataInputStream.On – w tym przypadku wybrano BufferedReader. Pozostaje nam tylko przekształcić strumień InputStream ze strumienia URL w strumień BufferedReader. Odbywa się to poprzez utworzenie strumienia pośredniego InputStreamReader:
BufferedReader is=new BufferedReader(new InputStreamReader(url.openStream()));
Utworzenie tego strumienia może się nie powieść. Obsługujemy odpowiedni wyjątek. Po uzyskaniu strumienia pozostaje nam już tylko odczytać z niego wiersze tekstu i wyświetlić je na ekranie.
String ligne;
while((ligne=is.readLine())!=null)
System.out.println(ligne);
Również w tym przypadku odczyt może spowodować wyjątek, który należy obsłużyć. Oto przykład uruchomienia programu, który wymaga lokalnego pliku URL:
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. Przykład graficzny
Interfejs graficzny będzie wyglądał następująco:

Numer | Nazwa | Typ | Rola |
1 | txtURL | JTextField | URL – do przeczytania |
2 | btnCharger | JButton | przycisk uruchamiający odtwarzanie pliku URL |
3 | JScrollPane1 | JScrollPane | pasek przewijania |
4 | lstURL | JList | lista wyświetlająca zawartość żądanego pliku URL |
Po uruchomieniu otrzymujemy wynik podobny do tego z programu konsolowego:

Odpowiedni kod aplikacji wygląda następująco:
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);
//Tworzenie ramki
public interfaceURL() {
..............
}
//Inicjalizacja komponentu
private void jbInit() throws Exception {
..............
}
//Zastąpiono, dzięki czemu możemy zakończyć działanie po zamknięciu okna
protected void processWindowEvent(WindowEvent e) {
...................
}
void txtURL_caretUpdate(CaretEvent e) {
// ustawia stan przycisku „Załaduj”
btnCharger.setEnabled(! txtURL.getText().trim().equals(""));
}
void btnCharger_actionPerformed(ActionEvent e) {
// wyświetla zawartość URL na liście
try{
afficherURL(txtURL.getText().trim());
}catch(Exception ex){
// wyświetla komunikat o błędzie
JOptionPane.showMessageDialog(this,"Erreur : " + ex.getMessage(),"Erreur",JOptionPane.ERROR_MESSAGE);
}//try-catch
}
private void afficherURL(String strURL) throws Exception {
// wyświetla zawartość URL strURL na liście
// żaden wyjątek nie jest obsługiwany w sposób specyficzny. Po prostu są one przekazywane dalej
// utworzenie pliku URL
URL url=new URL(strURL);
// utworzenie strumienia wejściowego
BufferedReader IN=new BufferedReader(new InputStreamReader(url.openStream()));
// odczyt wierszy tekstu ze strumienia wejściowego
String ligne;
while((ligne=IN.readLine())!=null)
lignes.addElement(ligne);
// zamknięcie strumienia odczytu
IN.close();
}
}
5.6.5.4. Aplet
Poprzednia aplikacja graficzna została przekształcona w aplet, tak jak to już wielokrotnie pokazywano. Aplet jest osadzony w dokumencie 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>

W powyższym przykładzie przeglądarka wysłała żądanie dotyczące pliku URL http://localhost:81/Japplets/2/appliURL.htm do serwera WWW apache działającego na porcie 81. Następnie aplet został wyświetlony w przeglądarce. W przeglądarce ponownie wysłano żądanie na adres http://localhost:81/Japplets/2/appliURL.htm, aby sprawdzić, czy rzeczywiście otrzymujemy plik appliURL.htm, który wcześniej utworzyliśmy. Teraz spróbujmy załadować plik URL, który nie pochodzi z komputera, na którym uruchomiono aplet (w tym przypadku localhost):

Ładowanie pliku URL zostało odrzucone. Mamy tu do czynienia z ograniczeniem dotyczącym apletów: mogą one uzyskać dostęp wyłącznie do zasobów sieciowych komputera, z którego zostały pobrane. Istnieje sposób, w jaki aplet może obejść to ograniczenie, polegający na przekazaniu żądań sieciowych do programu serwerowego znajdującego się na komputerze, z którego został pobrany. Program ten będzie wysyłał żądania sieciowe w imieniu apletu i przesyłał mu wyniki. Nazywa się to programem przekaźnikowym.
5.7. Aplet IMPOTS
Teraz przekształcimy aplikację graficzną IMPOTS w aplet. Ma to pewne zalety: aplikacja stanie się dostępna dla każdego internauty posiadającego przeglądarkę i wtyczkę Java 1.4 (dzięki komponentowi JSpinner). W ten sposób nasza aplikacja zyskuje globalny zasięg... Ta modyfikacja będzie wymagała nieco więcej niż tylko klasycznej już konwersji aplikacji graficznej na aplet. Aplikacja korzysta z opcji menu Initialiser, której celem jest odczytanie zawartości pliku lokalnego. Jeśli jednak wyobrazimy sobie aplikację internetową, widzimy, że ten schemat już nie ma zastosowania:

Oczywiste jest, że dane określające stawki podatkowe będą znajdować się na serwerze internetowym, a nie na każdym z komputerów klienckich. Plik, który ma zostać odczytany z serwera internetowego, zostanie umieszczony w tym samym folderze co aplet, a opcja Initialiser będzie musiała go stamtąd pobrać. Poprzednie przykłady pokazały, jak to zrobić. Ponadto do lokalnego wybierania pliku z danymi używano wcześniej komponentu JFileChooser, który w tym przypadku nie jest już potrzebny.
Dokument HTML zawierający aplet będzie wyglądał następująco:
<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">
Należy zwrócić uwagę na parametr data, którego wartość stanowi nazwę pliku zawierającego dane dotyczące stawek podatkowych. Dokument HTML, klasa appletImpots, klasa impots oraz plik impots.txt znajdują się w tym samym folderze na serwerze WWW:
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
Kod apletu wygląda następująco (wyróżniliśmy jedynie zmiany w stosunku do aplikacji graficznej):
...........
import java.net.*;
import java.applet.Applet;
public class appletImpots extends JApplet {
// elementy okna
JPanel contentPane;
............................
// atrybuty klasy
double[] limites=null;
double[] coeffr=null;
double[] coeffn=null;
impots objImpots=null;
String urlDATA=null;
//Tworzenie ramki
public void init() {
//enableEvents(AWTEvent.WINDOW_EVENT_MASK);
try {
jbInit();
}
catch(Exception e) {
e.printStackTrace();
}
// inne inicjalizacje
moreInit();
}
// inicjalizacja formularza
private void moreInit(){
// menu „Oblicz” wyłączone
mnuCalculer.setEnabled(false);
................
// pobierana jest nazwa pliku z tabelą podatkową
String nomFichier=getParameter("data");
// błąd?
if(nomFichier==null){
// komunikat o błędzie
txtStatus.setText("Le paramètre data de l'applet n'a pas été initialisé");
// blokowanie opcji „Inicjalizuj”
mnuInitialiser.setEnabled(false);
// koniec
return;
}//if
// ustawiamy URL danych
urlDATA=getCodeBase()+"/"+nomFichier;
}//moreInit
//Zainicjuj komponent
private void jbInit() throws Exception {
...................
}
void mnuQuitter_actionPerformed(ActionEvent e) {
// zamykamy aplikację
System.exit(0);
}
void mnuInitialiser_actionPerformed(ActionEvent e) {
// wczytanie pliku danych
try{
// odczyt danych
lireDATA();
// tworzenie obiektu „podatki”
objImpots=new impots(limites,coeffr,coeffn);
................
}
private void lireDATA() throws Exception {
// tabele danych
ArrayList aLimites=new ArrayList();
ArrayList aCoeffR=new ArrayList();
ArrayList aCoeffN=new ArrayList();
String[] champs=null;
// otwieranie pliku w trybie odczytu
BufferedReader IN=new BufferedReader(new InputStreamReader(new URL(urlDATA).openStream()));
// odczyt pliku wiersz po wierszu
....................
}
void mnuCalculer_actionPerformed(ActionEvent e) {
// obliczanie podatku
......................
}
void txtSalaire_caretUpdate(CaretEvent e) {
..........
}
void mnuEffacer_actionPerformed(ActionEvent e) {
...............
}
}
W tym miejscu omówimy jedynie zmiany wynikające z faktu, że plik danych do odczytania znajduje się obecnie na komputerze zdalnym, a nie lokalnym:
Nazwę pliku danych do odczytania, np. URL, uzyskuje się za pomocą następującego kodu:
// pobieranie nazwy pliku z tabelą podatkową
String nomFichier=getParameter("data");
// błąd?
if(nomFichier==null){
// komunikat o błędzie
txtStatus.setText("Le paramètre data de l'applet n'a pas été initialisé");
// blokowanie opcji „Inicjalizuj”
mnuInitialiser.setEnabled(false);
// koniec
return;
}//if
// ustawiamy URL danych
urlDATA=getCodeBase()+"/"+nomFichier;
Pamiętajmy, że nazwa pliku „impots.txt” została przekazana w parametrze data apletu:
Powyższy kod rozpoczyna się zatem od pobrania wartości parametru data, obsługując ewentualny błąd. Jeśli wartość parametru URL w dokumencie HTML zawierającym aplet wynosi http://localhost:81/JApplets/impots/appletImpots.htm, to URL z pliku impots.txt będzie miał nazwę http://localhost:81/JApplets/impots/impots.txt. Musimy utworzyć nazwę tego pliku URL. Metoda getCodeBase() apletu zwraca URL z folderu, z którego pobrano dokument HTML zawierający aplet, a więc w naszym przykładzie http://localhost:81/JApplets/impots. Poniższa instrukcja pozwala zatem utworzyć URL pliku danych:
W metodzie lireFichier(), która odczytuje zawartość pliku URL oraz urlData, znajduje się kod tworzący strumień wejściowy, który umożliwi odczytanie danych:
// otwieranie pliku do odczytu
BufferedReader IN=new BufferedReader(new InputStreamReader(new URL(urlDATA).openStream()));
Od tego momentu nie da się już odróżnić, czy dane pochodzą z pliku zdalnego, czy lokalnego. Oto przykład działania apletu:

5.8. Wnioski
W niniejszym rozdziale przedstawiono
- wprowadzenie do tworzenia interfejsów graficznych za pomocą JBuilder
- najpopularniejsze komponenty Swing
- tworzenie apletów
Warto zapamiętać, że
- kod wygenerowany przez JBuilder można napisać ręcznie. Po uzyskaniu tego kodu w dowolny sposób wystarczy proste JDK, aby go uruchomić, a JBuilder nie jest już niezbędne.
- korzystanie z narzędzia takiego jak JBuilder może przynieść znaczny wzrost wydajności:
- chociaż możliwe jest ręczne napisanie kodu wygenerowanego przez JBuilder, może to zająć dużo czasu i nie ma większego sensu, ponieważ logika aplikacji zazwyczaj leży gdzie indziej.
- Wygenerowany kod może być pouczający. Jego przeczytanie i przeanalizowanie to dobry sposób na poznanie niektórych metod i właściwości komponentów, z których korzystamy po raz pierwszy.
- JBuilder jest wieloplatformowy. Dzięki temu zachowujemy zdobytą wiedzę, przechodząc z jednej platformy na drugą. Możliwość pisania programów działających zarówno w systemie Windows, jak i Linux jest oczywiście bardzo ważnym czynnikiem wpływającym na wydajność. Wynika to jednak z samej języka Java, a nie z JBuilder.
5.9. JBuilder w systemie Linux
Wszystkie powyższe przykłady zostały przetestowane w systemie Windows 98. Można się zastanawiać, czy napisane programy są w tej postaci przenośne na system Linux. Są one przenośne, pod warunkiem że dany komputer z systemem Linux posiada klasy wykorzystywane przez poszczególne programy. Jeśli na przykład zainstalowali Państwo JBuilder w systemie Linux, niezbędne klasy znajdują się już na Państwa komputerze. Oto przykładowy wynik uruchomienia jednego z naszych programów na komponencie JList wraz z JBuilder 4 w systemie Linux:
Poniżej przedstawiamy instalację komponentu JBuilder 4 Foundation na komputerze z systemem Linux. Jego instalacja na komputerze z systemem Win9x przebiega bez problemów i jest analogiczna do procesu, który zostanie teraz opisany. Instalacja późniejszych wersji jest prawdopodobnie inna, ale niniejszy dokument może mimo to zawierać kilka przydatnych informacji.
JBuilder jest dostępny na stronie internetowej firmy Inprise pod adresem http://www.inprise.com/jbuilder

Na tej stronie znajdują się linki m.in. do wersji dla systemów Windows i Linux. Opiszemy teraz instalację programu JBuilder na komputerze z systemem Linux wyposażonym w interfejs graficzny KDE.
Po kliknięciu linku „Jbuilder 4 for Linux” wyświetla się formularz. Należy go wypełnić, a na koniec otrzymamy dwa pliki:
jb4docs_fr.tar.gz: dokumentacja i przykłady dotyczące JBuilder 4
jb4fndlinux_fr.tar.gz: JBuilder 4 Foundation. Jest to wersja ograniczona komercyjnego JBuildera 4, ale wystarczająca do celów edukacyjnych.
Klucz aktywacyjny oprogramowania zostanie wysłany pocztą elektroniczną. Umożliwi on korzystanie z JBuilder 4 i będzie wymagany przy pierwszym uruchomieniu. W przypadku utraty tego klucza można powrócić na powyższą stronę i kliknąć link „get your activation key”. Zakładamy, że posiadasz plik root i znajdujesz się w katalogu zawierającym dwa powyższe pliki tar.gz. Rozpakowujemy oba pliki:
[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
W obu wygenerowanych katalogach plik .bin jest plikiem instalacyjnym. Ponadto w przeglądarce należy wyświetlić plik index.html z każdego z katalogów. Zawierają one instrukcje dotyczące instalacji obu produktów. Zacznijmy od instalacji JBuilder Foundation:
Pojawi się pierwszy ekran instalacji. Potem pojawi się wiele kolejnych:

Potwierdź. Pojawi się ekran z wyjaśnieniami:

Wprowadź [suivant].

Zaakceptuj umowę licencyjną i wykonaj polecenie [suivant].

Zaakceptuj proponowaną lokalizację dla JBuilder (zapisz ją, będzie potrzebna później) i wykonaj polecenie [suivant]. Instalacja przebiega szybko.

Jesteśmy gotowi do pierwszego testu. W KDE uruchom menedżera plików, aby przejść do katalogu plików wykonywalnych JBuildera: /opt/jbuilder4/bin (jeśli zainstalowałeś JBuildera w /opt/jbuilder4):

Kliknij ikonę jbuilder powyżej. Ponieważ jest to pierwsze uruchomienie programu JBuilder, konieczne będzie wprowadzenie klucza aktywacyjnego:

Wypełnij pola Nom i Société. Kliknij [Ajouter], aby wprowadzić klucz aktywacyjny. Przypominamy, że klucz ten powinien zostać wysłany pocztą elektroniczną, a w przypadku jego utraty można go odzyskać pod adresem URL, z którego pobrano program JBuilder 4 (patrz początek instalacji). Po zaakceptowaniu klucza aktywacyjnego wyświetlą się warunki licencji:

Wpisując OK, powrócisz do okna wprowadzania danych, które już widziałeś:

Wprowadź OK, aby zakończyć ten etap, który jest wykonywany tylko przy pierwszym uruchomieniu. Następnie pojawi się środowisko programistyczne JBuilder:

Zamknij JBuilder, aby zainstalować dokumentację. Zostanie zainstalowanych kilka plików, które będą wykorzystywane w pomocy JBuildera, która na razie jest niekompletna. Wróć do katalogu, w którym rozpakowałeś pliki JBuildera o nazwie tar.gz. Program instalacyjny znajduje się w katalogu docs. Przejdź do niego:
[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
Plik instalacyjny nosi nazwę doc_install.bin, ale nie można go uruchomić od razu. Jeśli to zrobisz, instalacja zakończy się niepowodzeniem bez wyraźnego powodu. Aby uzyskać dokładny opis procedury instalacji, należy otworzyć plik index.html w przeglądarce. Instalator wymaga wirtualnej maszyny Java, a konkretnie programu o nazwie java, który musi znajdować się w katalogu PATH na Państwa komputerze. Przypominamy, że PATH jest zmienną systemu Unix, której wartość w postaci rep1:rep2:...:repn wskazuje katalogi repi, które należy przeszukać w poszukiwaniu pliku wykonywalnego. W tym przypadku instalator żąda uruchomienia programu o nazwie java. Możesz mieć kilka wersji tego programu, w zależności od liczby wirtualnych maszyn Java, które zainstalowałeś tu i ówdzie. Całkiem logicznie, użyjemy tej dostarczonej przez Jbuilder4, która znajduje się w katalogu /opt/jbuilder4/jdk1.3/bin. Aby umieścić ten katalog w zmiennej PATH:
[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
Teraz możemy rozpocząć instalację dokumentacji:
Rozpocznie się instalacja z interfejsem graficznym:

Jest ona bardzo podobna do instalacji programu JBuilder Foundation. Nie będziemy więc jej szczegółowo opisywać. Jest jednak jeden ekran, którego nie można pominąć:

Instalator powinien zazwyczaj samodzielnie wykryć lokalizację, w której zainstalowano JBuilder Foundation. Nie należy zatem zmieniać proponowanych ustawień, chyba że są one nieprawidłowe.
Po zainstalowaniu dokumentacji jesteśmy gotowi do przeprowadzenia kolejnego testu programu JBuilder. Uruchom aplikację zgodnie z instrukcją podaną powyżej. Po uruchomieniu programu JBuilder wybierz opcję Pomoc/Tematy pomocy. W lewym panelu kliknij link Tutoriels:

JBuilder zawiera zestaw samouczków, które pomogą Ci rozpocząć programowanie w języku Java. Poniżej przedstawiono samouczek „Tworzenie aplikacji” opisany powyżej.

W programie JBuilder wybierz opcję Plik/Nowy projekt. Kreator wyświetli trzy ekrany:

Stworzymy proste okno z tytułem „Witajcie wszyscy”. Nazwiemy ten projekt coucou. Przykład został uruchomiony przez root. JBuilder proponuje wówczas zebranie wszystkich projektów w katalogu jbproject znajdującym się w katalogu połączenia root. Projekt coucou zostanie umieszczony w katalogu coucou (pole „Nazwa katalogu projektu”) projektu jbproject. Utwórz projekt [suivant].

Ten drugi ekran stanowi podsumowanie różnych ścieżek w projekcie. Nie ma potrzeby wprowadzania żadnych zmian. Wybierz opcję [suivant].

Na trzecim ekranie pojawia się prośba o dostosowanie projektu. Wypełnij dane i wybierz opcję [Terminer].
Teraz uruchom Fichier/Nouveau:

Wybierz Application i wykonaj OK. Nowy kreator wyświetli dwa ekrany:

Pole paquet zawiera nazwę projektu. W polu „klasa” należy wpisać nom, które zostanie przypisane do głównej klasy projektu. Wpisz powyższą nazwę i wprowadź [suivant]:

Nasza aplikacja zawiera drugą klasę Java przeznaczoną dla okna aplikacji. Nadaj nazwę tej klasie. Pole Titre to tytuł, jaki chcesz nadać temu oknu. Ramka options zawiera opcje dotyczące okna. Wybierz je wszystkie i wprowadź [Terminer]. Następnie powrócisz do środowiska JBuilder, które zostało wzbogacone o informacje podane przez Ciebie dla Twojego projektu:

W lewym górnym oknie (1) znajduje się lista plików tworzących projekt. Znajdują się tam między innymi dwie klasy o nazwie .java, którą właśnie nadaliśmy. W prawym oknie (2) widoczny jest kod Java klasy coucouCadre. W lewym dolnym oknie widoczna jest struktura (klasy, metody, atrybuty) projektu. Projekt jest gotowy do uruchomienia. Naciśnij przycisk 4 powyżej, wybierz opcję Uruchom/Uruchom projekt lub wpisz F9. Powinno pojawić się następujące okno:

Po kliknięciu opcji Aide powinny pojawić się informacje, które podałeś w kreatorach. Nie będziemy się tym dalej zajmować. Nadszedł czas, abyś zagłębił się w samouczki.
Zanim zakończymy, pokażmy tylko, że można korzystać nie z JBuildera i jego interfejsu graficznego, ale z pakietu JDK, który został dostarczony wraz z nim i umieszczony w katalogu /opt/jbuilder4/jdk1.3. Skompiluj następujący plik essai1.java:
import java.io.*;
public class essai1{
public static void main(String args[]){
System.out.println("coucou");
System.exit(0);
}
}
Skompilujmy to i uruchommy za pomocą środowiska JDK w JBuilderze:






