1
Disciplina: Metode avansate de programare
Cadru didactic: Ralf Fabian
Specializarea: Informatic, anul II.
Interfaa grafic n Java
Interfaa grafic cu utilizatorul (GUI), este un termen cu neles larg care se refer la toate tipurile de comunicare vizual ntre un program i utilizatorii si. De la apariia limbajului Java, bibliotecile de clase care ofer servicii grafice au suferit probabil cele mai mari schimbri n trecerea de la o versiune la alta. Acest lucru se datoreaz, pe de o parte dificultii legate de implementarea noiunii de portabilitate, pe de alt parte nevoii de a integra mecanismele GUI cu tehnologii aprute i dezvoltate ulterior, cum ar fi Java Beans. In momentul actual, exist dou modaliti de a crea o aplicaie cu interfa grafic i anume:
AWT (Abstract Windowing Toolkit) - este API-ul iniial pus la dispoziie ncepnd cu primele versiuni de Java;
Swing - parte dintr-un proiect mai amplu numit JFC (Java Foundation Classes) creat n urma colaborrii dintre Sun, Netscape i IBM, Swing se bazeaz pe modelul AWT, extinznd funcionalitatea acestuia i adugnd sau nlocuind componente pentru dezvoltarea aplicaiilor GUI.
Este de preferat ca aplicaiile Java s fie create folosind tehnologia Swing, aceasta punnd la dispoziie o palet mult mai larg de faciliti, ns nu se renun complet la AWT deoarece aici exist clase eseniale, reutilizate n Swing.
In principiu, crearea unei aplicaii grafice presupune urmtoarele lucruri: 1. Design
Crearea unei suprafee de afiare (cum ar fi o fereastr) pe care vor fi aezate obiectele grafice (componente) care servesc la comunicarea cu utilizatorul (butoane,
controale pentru editarea textelor, liste, etc);
Crearea i aezarea componentelor pe suprafaa de afiare la poziiile corespunztoare;
2. Funcionalitate
Definirea unor aciuni care trebuie s se execute n momentul cnd utilizatorul interacioneaz cu obiectele grafice ale aplicaiei;
Ascultarea evenimentelor generate de obiecte n momentul interaciunii cu utilizatorul i executarea aciunilor corespunztoare, aa cum au fost ele definite.
Universitatea Lucian Blaga din Sibiu
Facultatea de tiine Departamentul de Matematic i Informatic
2
Ierarhia de componente AWT
Componente AWT
3
Ierarhia de componete Swing
Componente Swing
4
Interfaa grafic cu pachetul AWT
Pachetul care ofer componente AWT este java.awt. Obiectele grafice sunt derivate din
Component, cu excepia meniurilor care descind din clasa MenuComponent.
Prin noiunea de component se nelege orice obiect care poate avea o reprezentare grafic i care poate interaciona cu utilizatorul. Exemple de componente sunt ferestrele, butoanele, listele, bare de defilare, etc. Toate componentele AWT sunt definite de clase proprii ce se gsesc n pachetul java.awt, clasa Component fiind superclasa abstract a tuturor acestor clase.
Crearea obiectelor grafice nu realizeaz automat i afiarea lor pe ecran. Mai nti ele trebuie aezate pe o suprafa de afiare, care poate fi o fereastr, i vor deveni vizibile n momentul n care suprafaa pe care sunt afiate va fi vizibil. O astfel de suprafa pe care sunt plasate componente se mai numete container i reprezint o instan a unei clase derivate din Container.
Clasa Container este o subclas aparte a lui Component, fiind la rndul ei superclasa tuturor
suprafeelor de afiare Java. n momentul n care utilizatorul a efectuat o aciune, componentele trebuie s genereze
evenimente n funcie de aciunea pe care au suferit-o (aciune transmis de la tastatur, mouse, etc.). ncepnd cu versiunea 1.1 a limbajului Java, evenimentele sunt instane ale claselor derivate din AWTEvent.
Un eveniment este produs de o aciune a utilizatorului asupra unui obiect grafic, deci evenimentele nu trebuie generate de programator. n schimb, ntr-un program trebuie specificat
codul care se execut la apariia unui eveniment. Tratarea evenimentelor se realizeaz prin intermediul unor clase de tip listener (asculttor, consumator de evenimente), clase care sunt definite n pachetul java.awt.event.
Exemplu 1. O fereastr cu dou butoane.
//varianta AWT
import java.awt.*;
public class FirstGUI{
public static void main ( String args []) {
// Crearea ferestrei - un obiect de tip Frame
Frame f = new Frame ("Prima mea fereastra");
// Setarea modului de dipunere a componentelor
f.setLayout (new FlowLayout());
// Crearea celor doua butoane
Button b1 = new Button ("OK");
Button b2 = new Button ("Cancel");
// Adaugarea butoanelor
f.add(b1);
f.add(b2);
f.pack();
// Afisarea fereastrei
f.setVisible(true);
}
}
//varianta Swing
import java.awt.*;
import javax.swing.*;
public class FirstGUISwing {
public static void main(String args[]) {
// Crearea ferestrei - un obiect de tip Frame
JFrame f = new JFrame("Prima mea fereastra");
// setarea actiune implicite de terminare a
// aplicatiei la inchiderea ferestrei
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
5
// Setarea modului de dipunere a componentelor
f.setLayout(new FlowLayout());
// Crearea celor doua butoane
JButton b1 = new JButton("OK");
JButton b2 = new JButton("Cancel");
// Adaugarea butoanelor
f.add(b1);
f.add(b2);
f.pack();
// Afisarea fereastrei
f.setVisible(true);
}
}
Att butoanele adugate ct i butonul de nchidere a ferestrei pot fi apsate, dar nu realizeaz nimic. Acest lucru se ntmpl deoarece nu s-a specificat nicieri codul care trebuie s se execute la apsarea acestor butoane. De asemenea, mai trebuie remarcat c nu s-a specificat nicieri dimensiunile ferestrei sau ale butoanelor i nici poziiile de amplasare. Cu toate acestea ele sunt plasate unul lng celalalt, fr s se suprapun iar suprafaa ferestrei este suficient de mare nct s cuprind ambele obiecte. Aceste fenomene sunt provocate de un obiect special de tip FlowLayout care se ocup cu gestionarea ferestrei i cu plasarea componentelor ntr-o anumit
ordine pe suprafaa ei. Aadar, modul de aranjare nu este o caracteristic a suprafeei de afiare ci, fiecare container are asociat un obiect care se ocup cu dimensionarea i dispunerea componentelor pe suprafaa de afiare i care se numete gestionar de poziionare (layout manager).
Generaliti despre componentele AWT n pachetul java.awt, se regsesc urmtoarele clasa de componente:
Button - butoane cu eticheta format dintr-un text pe o singur linie;
Canvas - suprafa pentru desenare;
Checkbox - component ce poate avea dou stri; mai multe obiecte de acest tip pot fi
grupate folosind clasa CheckBoxGroup;
Choice - liste n care doar elementul selectat este vizibil i care se deschid la apsarea lor;
Container - superclasa tuturor suprafeelor de afiare;
Label - etichete simple ce pot conine o singur linie de text needitabil;
List - liste cu selecie simpl sau multipl;
Scrollbar - bare de defilare orizontale sau verticale;
TextComponent - superclasa componentelor pentru editarea textului: TextField (pe o
singur linie) i TextArea (pe mai multe linii).
Din cauza unor diferene eseniale n implementarea meniurilor pe diferite platforme de operare, acestea nu au putut fi integrate ca obiecte de tip Component, superclasa care
descrie meniuri fiind MenuComponent.
6
Componentele AWT au peste 100 de metode comune, motenite din clasa Component. Acestea
servesc uzual pentru aflarea sau setarea atributelor obiectelor, cum ar fi: dimensiune, poziie, culoare, font, etc. i au formatul general getProprietate, respectiv setProprietate. Cele mai folosite, grupate pe tipul proprietii gestionate sunt:
Poziie getLocation, getX, getY, getLocationOnScreen,
setLocation, setX, setY
Dimensiuni getSize, getHeight, getWidth
setSize, setHeight, setWidth
Dimensiuni i poziie getBounds
setBounds
Culoare getForeground, getBackground
setForeground, setBackground
Font getFont
setFont
Vizibilitate setVisible
isVisible
Interactivitate setEnabled
isEnabled
Generaliti despre suprafee de afiare Mai nti obiectele grafice trebuie aezate pe o suprafa, i vor deveni vizibile n momentul
n care suprafaa respectiv va fi vizibil. O astfel de suprafa pe care sunt plasate componentele se numete suprafaa de afiare sau container i reprezint o instan a unei clase derivat din Container.
O parte din clasele care au drept printe pe Container sunt urmtoarele:
Window - este superclasa tuturor ferestrelor. Din aceast clas sunt derivate:
Frame - ferestre standard;
Dialog - ferestre de dialog modale sau nemodale;
Panel - o suprafa fr reprezentare grafic folosit pentru gruparea altor componente. Din
aceast clas deriv Applet, folosit pentru crearea appleturilor.
7
ScrollPane - container folosit pentru implementarea automat a derulrii pe orizontal sau
vertical a unei componente.
Componentele adugate sunt memorate ntr-o list iar poziiile lor din aceast list vor defini ordinea de traversare front-to-back a acestora n cadrul containerului. Dac nu este specificat nici un index la adugarea unei componente, atunci ea va fi adugat pe ultima poziie a listei.
Clasa Container conine metodele comune tuturor suprafeelor de afiare. Cele mai
folosite sunt:
add - permite adugarea unei componente pe suprafaa de afiare. O component nu poate
aparine dect unui singur container, ceea ce nseamn c pentru a muta un obiect dintr-un container n altul trebuie eliminat mai nti de pe containerul iniial.
remove - elimin o component de pe container;
setLayout - stabilete gestionarul de poziionare al containerului;
getInsets - determin distana rezervat pentru marginile suprafeei de afiare;
validate - foreaz containerul s reaeze toate componentele sale. Aceast metod
trebuie apelat explicit atunci cnd se adaug sau se elimin componente pe suprafa de afiare dup ce aceasta a devenit vizibil.
Frame f = new Frame("O fereastra");
// Adauga un buton direct pe fereastra
Button b = new Button("Hello");
f.add(b);
// Adauga doua componente pe un panel
Label et = new Label("Nume:");
TextField text = new TextField();
Panel panel = new Panel();
panel.add(et);
panel.add(text);
// Adauga panel-ul pe fereastra i, indirect, cele doua componente
f.add(panel);
Gestionarea poziionrii Un gestionar de poziionare (layout manager) este un obiect care controleaz dimensiunea
i aranjarea (poziia) componentelor unui container. Aadar, modul de aranjare a componentelor pe o suprafaa de afiare nu este o caracteristica a clasei Container. Fiecare obiect de tip
Container, sau o extensie a lui (Applet, Frame, Panel) are asociat un obiect care se ocupa
cu dispunerea componentelor pe suprafaa sa: gestionarul de poziionare. Toate clasele care instaniaz obiecte pentru gestionarea poziionrii implementeaz interfaa LayoutManager. La
8
instanierea unui container se creeaz implicit un gestionar de poziionare asociat acestui container. De exemplu pentru o fereastra (un obiect de tip Window sau o subclasa a sa) gestionarul implicit
este de tip BorderLayout, n timp ce pentru un container de tip Panel este o instan a clasei
FlowLayout.
Folosirea gestionarilor de poziionare
Orice container are un gestionar implicit de poziionare - un obiect care implementeaz interfaa LayoutManager, acesta fiindu-i ataat automat la crearea sa. n cazul n care acesta nu
corespunde necesitilor noastre el poate fi schimbat cu uurin. Cei mai utilizai gestionari din pachetul java.awt sunt:
FlowLayout
BorderLayout
GridLayout
CardLayout
Ataarea explicit a unui gestionar de poziionare la un container se face cu metoda setLayout a
clasei Container. Metoda poate primi ca parametru orice instan a unei clase care implementeaz
interfaa LayoutManager. Secvena de ataare a unui gestionar pentru un container este:
FlowLayout gestionar = new FlowLayout();
container.setLayout(gestionar);
sau, mai uzual : container.setLayout(new FlowLayout());
Programele nu apeleaz n general metode ale gestionarilor de poziionare iar n cazul cnd avem nevoie de obiectul gestionar l putem obine cu metoda getLayout din clasa Container.
Una din facilitile cele mai utile oferite de gestionarii de poziionare este rearanjarea componentele unui container atunci cnd acesta este redimensionat. Poziiile i dimensiunile componentelor nu sunt fixe, ele fiind ajustate automat de ctre gestionar la fiecare redimensionare astfel nct sa ocupe ct mai estetic suprafaa de afiare.
Pentru situaii n care se dorete o amplasare a componentelor la anumite poziii fixe, iar acestea s rmn acolo chiar dac se redimensioneaz containerul, se trimite argumentului null
metodei setLayout:
//pozitionare absoluta a componentelor in container
container.setLayout(null);
Folosind poziionarea absoluta, nu va mai fi suficient adugarea cu metoda add a
componentelor n container ci va trebui specificat poziia i dimensiunea lor - acest lucru era fcut automat de gestionarul de poziionare.
container.setLayout( null );
Button b = new Button("Buton");
b.setSize(10, 10);
b.setLocation (0, 0);
b.add();
In general, se recomanda folosirea gestionarilor de poziionare n toate situaiile cnd acest lucru este posibil, deoarece permit programului sa aib aceeai nfiare indiferent de platforma i rezoluia pe care este rulat.
9
Gestionarul FlowLayout
Acest gestionar aeaz componentele pe suprafaa de afiare n flux liniar, mai precis, componentele sunt adugate una dup alta pe linii, n limita spaiului disponibil. In momentul cnd o componenta nu mai ncape pe linia curenta se trece la urmtoarea linie, de sus n jos. Adugarea componentelor se face de la stnga la dreapta pe linie, iar alinierea obiectelor n cadrul unei linii poate fi de trei feluri: la stnga, la dreapta, centrate. Implicit componentele sunt centrate
pe fiecare linie iar distanta implicita ntre componente este de 5 uniti pe verticala i 5 pe orizontal.
Exemplu 2.
import java.awt.*;
import javax.swing.*;
public class TestFlowLayout {
public static void main(String args[]) {
JFrame f = new JFrame("Flow Layout");
f.setLayout(new FlowLayout());
JButton b1 = new JButton("Button 1");
JButton b2 = new JButton("2");
JButton b3 = new JButton("Button 3");
JButton b4 = new JButton("Long-Named Button 4");
JButton b5 = new JButton("Button 5");
f.add(b1); f.add(b2); f.add(b3); f.add(b4); f.add(b5);
f.pack();
f.setVisible(true);
}
} Componentele ferestrei vor fi afiate astfel:
Redimensionnd fereastra astfel nct cele cinci butoane sa nu mai ncap pe o linie, ultimele dintre ele vor fi trecute pe linia urmtoare:
Gestionarul BorderLayout
Gestionarul BorderLayout mparte suprafaa de afiare n cinci regiuni, corespunztoare
celor patru puncte cardinale i centrului. O componenta poate fi plasata n oricare din aceste regiuni,
10
dimensiunea componentei fiind calculata astfel nct sa ocupe ntreg spaiul de afiare oferit de regiunea respectiva. Pentru a aduga mai multe obiecte grafice ntr-una din cele cinci zone, ele trebuie grupate n prealabil ntr-un panel, care va fi amplasat apoi n regiunea dorita.
Aadar, la adugarea unei componente pe o suprafa gestionat de BorderLayout, metoda add
va mai primi pe lng numele componentei i zona n care aceasta va fi amplasata, acesta fiind specificat prin una din constantele clasei BorderLayout: NORTH, SOUTH, EAST, WEST,
CENTER.
Exemplu 3.
import java.awt.BorderLayout;
import javax.swing.*;
import static java.awt.BorderLayout.*;
public class TestBorderLayout {
public static void main(String args[]) {
JFrame f = new JFrame("Border Layout");
// poate sa lipseasca, e implicit la JFrame
f.setLayout(new BorderLayout());
f.add(new JButton("Nord"), NORTH);
f.add(new JButton("Sud"), SOUTH);
f.add(new JButton("Est"), EAST);
f.add(new JButton("Vest"), WEST);
f.add(new JButton("Centru"), CENTER);
f.pack();
f.setVisible(true);
}
} Cele cinci butoane ale ferestrei vor fi afiate astfel:
La redimensionarea ferestrei se pot observa urmtoarele lucruri: nordul i sudul se redimensioneaz doar pe orizontala, estul i vestul doar pe verticala, n timp ce centrul se redimensioneaz att pe orizontala ct i pe verticala. Redimensionarea componentelor se face astfel nct ele ocupa toat zona containerului din care fac parte.
Gestionarul GridLayout
Gestionarul GridLayout organizeaz containerul ca un tabel cu rnduri i coloane,
componentele fiind plasate n csuele tabelului de la stnga la dreapta ncepnd cu primul rnd. Csuele tabelului au dimensiuni egale iar o component poate ocupa doar o singura csu. Numrul de linii i coloane poate fi specificat n constructorul gestionarului dar poate fi modificat i ulterior prin metodele setRows i setCols. De asemenea, distanta ntre componente pe orizontala
i distanta ntre rndurile tabelului pot fi specificate n constructor sau stabilite ulterior.
Exemplu 4.
11
import java.awt.*;
import javax.swing.*;
public class TestGridLayout {
public static void main(String args[]) {
JFrame f = new JFrame("Grid Layout");
f.setLayout(new GridLayout(3, 2));
f.add(new JButton("Button 1"));
f.add(new JButton("2"));
f.add(new JButton("Button 3"));
f.add(new JButton("Long-Named Button 4"));
f.add(new JButton("Button 5"));
f.pack();
f.setVisible(true);
}
}
Cele cinci butoane ale ferestrei vor fi pe trei rnduri i doua coloane astfel:
Redimensionarea ferestrei va determina redimensionarea tuturor componentelor.
Gestionarul CardLayout
Gestionarul CardLayout trateaz componentele adugate pe suprafaa sa ntr-o manier
similar cu cea a dispunerii crilor de joc ntr-un pachet. Suprafaa de afiare poate fi asemnat cu pachetul de cri iar fiecare component este o carte din pachet. La un moment dat, numai o singur component este vizibil.
Clasa dispune de metode prin care s poat fi afiat o anumit component din pachet, sau s se poat parcurge secvenial pachetul, ordinea componentelor fiind intern gestionarului.
Principala utilitate a acestui gestionar este utilizarea mai eficient a spaiului disponibil n situaii n care componentele pot fi grupate n aa fel nct utilizatorul s interacioneze la un moment dat doar cu un anumit grup (o carte din pachet), celelalte fiind ascunse.
Exemplu 5. Aplicaia arat modul de funcionare a unui CardLayout. Clasa TestCardLayout
particularizeaz clasa JFrame prin motenire. Sunt tratate evenimentele de click pe dou butoane
prin implementarea interfeei asculttor ActionListener. // ontine si tratarea de evenimente pt. 2 butoane
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
public class TestCardLayout extends JFrame implements ActionListener {
JPanel tab;
public TestCardLayout() {
super("TestCardLayout");
JButton card1 = new JButton("Card 1");
JButton card2 = new JButton("Card 2");
JPanel butoane = new JPanel();
12
butoane.add(card1);
butoane.add(card2);
// partea care se va ascunde
JLabel et = new JLabel("Nume:");
JTextField text = new JTextField(20);
JPanel panel = new JPanel();
panel.add(et);
panel.add(text);
tab = new JPanel();
tab.setLayout(new CardLayout());
TextField tf = new TextField("Text Field");
tab.add("Card 1", tf);
tab.add("Card 2", panel);
add(butoane, BorderLayout.NORTH);
add(tab, BorderLayout.CENTER);
// adaugarea de ascultatoare pt. evenimente
card1.addActionListener(this);
card2.addActionListener(this);
pack();
}
public void actionPerformed(ActionEvent e) {
CardLayout gestionar = (CardLayout) tab.getLayout();
gestionar.show(tab, e.getActionCommand());
}
public static void main(String args[]) {
new TestCardLayout().setVisible(true);
}
}
Rezultatul acestui exemplu arata grafic astfel:
Gruparea componentelor (Clasa Panel)
Plasarea componentelor direct pe suprafaa de afiare poate deveni incomoda n cazul n care avem multe obiecte grafice. Din acest motiv se recomanda gruparea obiectelor grafice nrudite
ca funcionalitate astfel nct sa putem fi siguri c, indiferent de gestionarul de poziionare al suprafeei de afiare, ele se vor gsi mpreun. Gruparea componentelor se face n panel-uri.
Un panel este cel mai simplu model de container. El nu are o reprezentare vizibila, rolul sau
fiind de a oferi o suprafa de afiare pentru componente grafice, inclusiv pentru alte panel-uri. Clasa care instaniaz aceste obiecte este Panel, extensie a superclasei Container. Pentru a aranja
corespunztor componentele grupate ntr-un panel, acestuia i se poate specifica un gestionar de poziionare anume, folosind metoda setLayout. Gestionarul implicit pentru containerele de tip
Panel este FlowLayout.
Aadar, o aranjare eficienta a componentelor unei ferestre nseamn:
gruparea componentelor nfrite (care nu trebuie sa fie desprite de gestionarul de poziionare al ferestrei) n panel-uri;
13
aranjarea componentelor unui panel, prin specificarea acestuia a unui gestionar de poziionare corespunztor
aranjarea panel-urilor pe suprafaa ferestrei, prin specificarea gestionarului de poziionare al ferestrei.
Exemplu 6.
import java.awt.*;
import javax.swing.*;
public class TestPanel {
public static void main(String args[]) {
JFrame f = new JFrame("Panel");
JPanel panel = new JPanel();
panel.setLayout(new FlowLayout());
panel.add(new JLabel("Text:"));
panel.add(new JTextField("", 20));
panel.add(new JButton("Reset"));
f.add(panel, BorderLayout.NORTH);
f.add(new JButton("OK"), BorderLayout.EAST);
f.add(new JButton("Cancel"), BorderLayout.WEST);
f.pack();
f.setVisible(true);
}
}
14
Evenimente n interfee grafice
ntr-o interfa grafic, eveniment este produs de o aciune a utilizatorului asupra unei componente grafice i reprezint mecanismul prin care utilizatorul comunic efectiv cu programul. Exemple de evenimente sunt: apsarea unui buton, modificarea textului ntr-un control de editare, nchiderea, redimensionarea unei ferestre, etc. Componentele care genereaz anumite evenimente se mai numesc i surse de evenimente.
Interceptarea evenimentelor generate de componentele unui program se realizeaz prin intermediul unor clase de tip listener (asculttor, consumator de evenimente). In Java, orice
obiect poate consuma evenimentele generate de o anumita component grafic.
Utilizator Component Listener (aciune) (generare de eveniment) (interceptarea evenimentului)
Aadar, pentru a scrie cod care s se execute n momentul n care utilizatorul interacioneaz cu o componenta grafic trebuie sa facem urmtoarele lucruri:
s scriem o clasa de tip Listener care s asculte evenimentele produse de acea
component i n cadrul acestei clase s implementm metode specifice pentru tratarea lor;
s comunicm componentei surs c respectiva clas i ascult evenimentele pe care le genereaz, cu alte cuvinte s nregistram acea clasa drept consumator al evenimentelor produse de componenta respectiv.
Evenimentele sunt, ca orice altceva n Java, obiecte. Clasele care descriu aceste obiecte se
mpart n mai multe tipuri n funcie de componenta care le genereaz, mai precis n funcie de aciunea utilizatorului asupra acesteia. Pentru fiecare tip de eveniment exist o clasa care instaniaz obiecte de acel tip; de exemplu: evenimentul generat de acionarea unui buton este implementat prin clasa ActionEvent, cel generat de modificarea unui text prin clasa TextEvent, etc.
Toate aceste clase au ca superclasa comuna clasa AWTEvent.
15
O clasa consumatoare de evenimente (listener) poate fi orice clasa care specifica n
declaraia sa ca dorete s asculte evenimente de un anumit tip. Acest lucru se realizeaz prin implementarea unei interfee specifice fiecrui tip de eveniment. Astfel, pentru ascultarea evenimentelor de tip ActionEvent clasa respectiv trebuie s implementeze interfaa
ActionListener, pentru TextEvent este TextListener, etc. Toate aceste interfee au
superinterfaa comun EventListener.
Se poate scrie ceva de forma:
class AscultaButoane implements ActionListener
class AscultaTexte implements TextListener
ntruct o clasa poate implementa oricte interfee ea va putea s asculte evenimente de mai multe tipuri:
class Ascultator implements ActionListener, TextListener
Vom vedea n continuare metodele fiecrei interfee pentru a ti ce trebuie s implementeze o clas consumatoare de evenimente.
Pentru ca evenimentele unei componente s fie interceptate de ctre o instan a unei clase asculttor, aceast clas trebuie nregistrat n lista asculttorilor componentei respective. nregistrarea unei clase n lista asculttorilor unei componente se face cu metode din clasa Component de tipul addYYYListener, iar eliminarea ei din aceast list cu
removeYYYListener unde YYY reprezenta tipul evenimentului.
Exemplu 1. O fereastra care s conin doua butoane cu numele OK, respectiv Cancel. La apsarea fiecrui buton se scrie pe bara de titlu a ferestrei mesajul Ati apasat butonul ...". import java.awt.*;
import java.awt.event.*;
class Fereastra extends JFrame {
public Fereastra(String titlu) {
super(titlu);
//se stabileste gestionarul
setLayout(new FlowLayout());
//se dimensioneaza fereastra
setSize(300, 100);
//se construiesc si se adauga butoanele Ok si Cancel
JButton b1 = new JButton("OK");
add(b1);
JButton b2 = new JButton("Cancel");
add(b2);
//se construieste un obiect de tip Ascultator.
//la creare este pasata o referinta spre obiectul curent
//pt. ca ascultatorul sa aiba acces la elementle obiectului
//pe care a aparut evenimentul
Ascultator listener = new Ascultator(this);
//ambele butoane sunt ascultate de obiectul "listener"
//instanta a clasei Ascultator, definita mai jos
b1.addActionListener(listener);
b2.addActionListener(listener);
}
}
16
//implementarea ascultatotului pentru butoanele aplicatiei
class Ascultator implements ActionListener {
//atribut care va retine o referinta spre obiectul
//care contine butoanele tratate
private Fereastra f;
//constructorul Ascultatorului
public Ascultator(Fereastra f) {
this.f = f;
}
//metoda interfetei ActionListener (unica)
public void actionPerformed(ActionEvent e) {
//se afla comanda din obiectul de eveniment
String command = e.getActionCommand();
//numele comenzii este numele butonului apasat
System.out.println(e.toString());
if (command.equals("OK"))
f.setTitle("Ati apasat OK");
else
if (command.equals("Cancel"))
f.setTitle("Ati apasat Cancel");
}
}
public class ListenOkCancel { //fereastra principala
public static void main(String args[]) {
Fereastra f = new Fereastra("Evenimente pe 2 butoane");
f.setVisible(true);
}
}
Nu este obligatoriu s definim clase speciale pentru ascultarea evenimentelor. In exemplul de mai sus am definit o clasa special Ascultator pentru a intercepta evenimentele produse de cele doua butoane i din acest motiv a trebuit s trimitem ca parametru acestei clase instana la fereastr. Mai uor ar fi fost s folosim chiar clasa Fereastra pentru a asculta evenimentele produse de componentele ei:
class Fereastra extends JFrame implements ActionListener{
public Fereastra(String titlu) {
super(titlu);
. . .
//ambele butoane sunt ascultate chiar din clasa Fereastra
//deci ascultatorul este instanta curenta: this
b1.addActionListener(this);
b2.addActionListener(this);
}
public void actionPerformed(ActionEvent e) {
String command = e.getActionCommand();
System.out.println(e.toString());
if (command.equals("OK"))
this.setTitle("Ati apasat OK");
else
if (command.equals("Cancel"))
this.setTitle("Ati apasat Cancel");
}
}
17
Aadar, orice clas poate asculta evenimente de orice tip cu condiia s implementeze interfeele specifice acelor evenimente.
Tipuri (clase) de evenimente si componentele care le genereaz In tabelul de mai jos sunt prezentate n stnga tipurile de evenimente i interfeele iar n
dreapta lista componentelor ce pot genera evenimente de acel tip precum i o scurt explicaie despre motivul care le provoac.
Eveniment/Interfa Componente care genereaz acest eveniment ActionEvent
ActionListener Button, List, TextField, MenuItem, CheckboxMenuItem, Menu,
PopupMenu
Aciuni asupra unui control AdjustmentEvent
AdjustmentListener Scrollbar i orice clasa care implementeaz interfaa Adjustable Modificarea unei valori variind ntre doua limite
ComponentEvent
ComponentListener Component si subclasele sale
Redimensionri, deplasri, ascunderi ale componentelor ContainerEvent
ContainerListener Container si subclasele sale
Adugarea, tergerea componentelor la un container FocusEvent
FocusListener Component si subclasele sale
Preluarea, pierderea focusului de ctre o componenta KeyEvent
KeyListener Component i subclasele sale Apsarea, eliberarea unei taste cnd focusul este pe o anumita componenta.
MouseEvent
MouseListener Component si subclasele sale
Click, apsare, eliberare a mouse-ului pe o componenta, intrarea, ieirea mouse-ului pe/de pe suprafaa unei componente
MouseEvent
MouseMotionListener Component si subclasele sale
Micarea sau drag-ul mouse-ului pe suprafaa unei componente WindowEvent
WindowListener Window si subclasele sale Dialog, FileDialog, Frame
nchiderea, maximizarea, minimizarea, redimensionarea unei ferestre ItemEvent
ItemListener Checkbox, CheckboxMenuItem, Choice, List i orice clasa care implementeaza interfata ItemSelectable
Selecia, deselecia unui articol dintr-o lista sau meniu. TextEvent
TextListener Orice clasa derivata din TextComponent cum ar fi : TextArea,
TextField
Modificarea textului dintr-o componenta de editare a textului
18
Evenimente suportate de o componenta
Urmtorul tabel prezint o clasificare a evenimentelor n funcie de componentele care le suport:
Componenta Evenimente suportate de componenta Adjustable AdjustmentEvent
Applet ContainerEvent, FocusEvent, KeyEvent, MouseEvent,
ComponentEvent
Button ActionEvent, FocusEvent, KeyEvent, MouseEvent,
ComponentEvent
Canvas FocusEvent, KeyEvent, MouseEvent, ComponentEvent
Checkbox ItemEvent, FocusEvent, KeyEvent, MouseEvent,
ComponentEvent
CheckboxMenuItem ActionEvent, ItemEvent
Choice ItemEvent, FocusEvent, KeyEvent, MouseEvent,
ComponentEvent
Component FocusEvent, KeyEvent, MouseEvent, ComponentEvent
Container ContainerEvent, FocusEvent, KeyEvent, MouseEvent,
ComponentEvent
Dialog ContainerEvent, WindowEvent, FocusEvent, KeyEvent,
MouseEvent, ComponentEvent
FileDialog ContainerEvent, WindowEvent, FocusEvent, KeyEvent,
MouseEvent, ComponentEvent
Frame ContainerEvent, WindowEvent, FocusEvent, KeyEvent,
MouseEvent, ComponentEvent
Label FocusEvent, KeyEvent, MouseEvent, ComponentEvent
List ActionEvent, FocusEvent, KeyEvent, MouseEvent,
ItemEvent, ComponentEvent
Menu ActionEvent
MenuItem ActionEvent
Panel ContainerEvent, FocusEvent, KeyEvent, MouseEvent,
ComponentEvent
PopupMenu ActionEvent
Scrollbar AdjustmentEvent, FocusEvent, KeyEvent, MouseEvent,
ComponentEvent
ScrollPane ContainerEvent, FocusEvent, KeyEvent, MouseEvent,
ComponentEvent
TextArea TextEvent, FocusEvent, KeyEvent, MouseEvent,
ComponentEvent
TextComponent TextEvent, FocusEvent, KeyEvent, MouseEvent,
ComponentEvent
TextField ActionEvent, TextEvent, FocusEvent, KeyEvent,
MouseEvent, ComponentEvent
Window ContainerEvent, WindowEvent, FocusEvent, KeyEvent,
MouseEvent, ComponentEvent
19
Metodele interfeelor de tip listener Orice clas care trateaz evenimente trebuie s implementeze obligatoriu metodele
interfeelor corespunztoare evenimentelor pe care le trateaz. Tabelul de mai jos prezint, pentru fiecare interfaa, metodele puse la dispoziie i care trebuie implementate de clasa asculttor.
Interfata Metodele interfetei ActionListener actionPerformed(ActionEvent)
AdjustmentListener adjustmentValueChanged(AdjustmentEvent)
ComponentListener componentHidden(ComponentEvent)
componentShown(ComponentEvent)
componentMoved(ComponentEvent)
componentResized(ComponentEvent)
ContainerListener componentAdded(ContainerEvent)
componentRemoved(ContainerEvent)
FocusListener focusGained(FocusEvent)
focusLost(FocusEvent)
KeyListener keyPressed(KeyEvent)
keyReleased(KeyEvent)
keyTyped(KeyEvent)
MouseListener mouseClicked(MouseEvent)
mouseEntered(MouseEvent)
mouseExited(MouseEvent)
mousePressed(MouseEvent)
mouseReleased(MouseEvent)
MouseMotionListener mouseDragged(MouseEvent)
mouseMoved(MouseEvent)
WindowListener windowOpened(WindowEvent)
windowClosing(WindowEvent)
windowClosed(WindowEvent)
windowActivated(WindowEvent)
windowDeactivated(WindowEvent)
windowIconified(WindowEvent)
windowDeiconified(WindowEvent)
ItemListener itemStateChanged(ItemEvent)
TextListener textValueChanged(TextEvent)
Folosirea adaptorilor i a claselor interne n tratarea evenimentelor O clas care trateaz evenimente de un anumit tip trebuie sa implementeze interfaa
corespunztoare acelui tip. Aceasta nseamn ca trebuie s implementeze obligatoriu toate metodele definite de acea interfa, chiar dac nu specific nici un cod pentru unele dintre ele. Sunt ns situaii cnd acest lucru este suprtor, mai ales atunci cnd nu ne intereseaz dect o singur metoda a interfeei.
Un exemplu sugestiv este urmtorul: o fereastra care nu are specificat cod pentru tratarea evenimentelor sale nu poate fi nchisa cu butonul standard marcat cu 'x' din colul dreapta sus i nici cu combinaia de taste Alt+F4. Pentru a realiza acest lucru trebuie interceptat evenimentul de nchidere a ferestrei n metoda windoClosing i apelat apoi metoda dispose de nchidere a
ferestrei, eventual urmat de ieirea din program, n cazul cnd este vorba de fereastra principala a aplicaiei. Aceasta nseamn c trebuie sa implementam interfaa WindowListener care are nu
mai puin de apte metode.
20
Exemplu 2. Crearea unei ferestre cu ascultarea evenimentelor sale folosind implementarea directa a
interfeei WindowListener.
import java.awt.*;
import java.awt.event.*;
class Fereastra extends JFrame implements WindowListener {
public Fereastra(String titlu) {
super(titlu);
this.addWindowListener(this);
}
//metodele interfetei WindowListener
public void windowOpened(WindowEvent e) {}
public void windowClosing(WindowEvent e) {
dispose(); //inchid fereastra
System.exit(0); //termin programul
}
public void windowClosed(WindowEvent e) {}
public void windowIconified(WindowEvent e) {}
public void windowDeiconified(WindowEvent e) {}
public void windowActivated(WindowEvent e) {}
public void windowDeactivated(WindowEvent e) {}
}
public class TestWindowListener {
public static void main(String args[]) {
Fereastra f = new Fereastra("O fereastra");
f.setVisible(true);
}
}
Se observ c trebuie implementate toate metodele interfeei, chiar dac nu se scriem nici un cod pentru ele. Singura metoda care intereseaz este windowClosing n care se specific ce
trebuie fcut atunci cnd utilizatorul dorete s nchid fereastra. Pentru a evita scrierea inutil a acestor metode exista o serie de clase care implementeaz interfeele de tip listener far a
specifica nici un cod pentru metodele lor. Aceste clase se numesc adaptori.
Utilizarea adaptorilor
Un adaptor este o clasa abstracta care implementeaz o interfa de tip listener. Scopul
unei astfel de clase este ca la crearea unui asculttor de evenimente, n loc s implementeze o anumita interfa i implicit toate metodele sale, se extinde adaptorul corespunztor interfeei respective i se supradefinete doar metodele care intereseaz (cele n care se scrie o anumit secven de cod).
De exemplu, adaptorul interfeei WindowListener este WindowAdapter iar folosirea
acestuia este data n exemplul de mai jos.
21
Exemplu 3. Crearea unei ferestre cu ascultarea evenimentelor sale folosind extinderea clasei
WindowAdapter.
import java.awt.*;
import java.awt.event.*;
class Fereastra extends JFrame {
public Fereastra(String titlu) {
super(titlu);
this.addWindowListener(new Ascultator());
}
}
class Ascultator extends WindowAdapter {
//suprdefinim metodele care ne intereseaza
public void windowClosing(WindowEvent e) {
//?.dispose();
// dispose nu se mai poate apela, de ce?
System.exit(0);
}
}
public class TestWindowAdapter {
public static void main(String args[]) {
Fereastra f = new Fereastra("O fereastra");
f.setVisible(true);
}
}
Avantajul clar al acestei modaliti de tratare a evenimentelor este reducerea codului programului, acesta devenind mult mai uor lizibil. nsa exist i doua dezavantaje majore.
Dup cum ai observat, faa de exemplul anterior clasa Fereastra nu poate extinde
WindowAdapter deoarece ea extinde deja clasa Frame i din acest motiv s-a construi o
noua clasa numit Ascultator. Acest dezavantaj poate fi eliminat prin folosirea unei clase
interne.
Un alt dezavantaj este c orice greeala de sintax n declararea unei metode a interfeei nu va produce o eroare de compilare dar nici nu va supradefini metoda interfeei ci, pur si simplu, va crea o metoda a clasei respective.
class Ascultator extends WindowAdapter {
//exemple de erori sintactice:
// in loc de windowClosing scriem WindowClosing
// nu supradefinim vreo metoda a clasei WindowAdapter
// nu da nici o eroare
// nu face nimic !
public void WindowClosing(WindowEvent e) {
System.exit(0);
}
}
22
n tabelul de mai jos sunt dai toi adaptorii interfeelor de tip listener - se observ c o
interfa YYYListener are un adaptor de tipul YYYAdapter. Interfeele care nu au un adaptor sunt
cele care definesc o singura metoda i prin urmare crearea unei clase adaptor nu i are rostul.
Interfaa "listener" Adaptor ActionListener nu are
AdjustmentListener nu are
ComponentListener ComponentAdapter
ContainerListener ContainerAdapter
FocusListener FocusAdapter
ItemListener nu are
KeyListener KeyAdapter
MouseListener Mouse
MouseMotionListener MouseMotionAdapter
TextListener nu are
WindowListener WindowAdapter
Folosirea claselor interne (anonime)
O clas interna este o clas declarata n cadrul altei clase iar clasele anonime sunt acele clase interne folosite doar pentru instanierea unui singur obiect de acel tip. Un exemplu tipic de folosire a lor este instanierea adaptorilor direct n corpul unei clase care conine componente ale cror evenimente trebuie interceptate. Clasa Fereastra din exemplul anterior poate fi scrisa astfel:
class Fereastra extends JFrame {
public Fereastra(String titlu) {
super(titlu);
this.addWindowListener(new WindowAdapter() {
//corpul clasei anonime
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
}
}
Codul programului a fost redus substanial prin folosirea unui adaptor i a unei clase anonime.
23
Java GUI API --- Swing
24