Mariusz Chmielewski
1
Programowanie
Zdarzeniowe
Komponenty Swing
Delegacyjny model
zdarzeń
Obsługa zdarzeń
kpt. mgr inż. Mariusz Chmielewski
Instytut Systemów Informatycznych
Wydział Cybernetyki
Wojskowa Akademia Techniczna
Delegacyjny model obsługi zdarzeń –
Delegation Event Model
• Prosta idea : źródło (source) generuje
zdarzenie (event), które jest wysyłane
do zarejestrowanych (jednego lub
wielu) obiektów nasłuchujących
(listener);
• Obiekt nasłuchujący oczekuje na
odebranie zdarzenia. W momencie jego
odebrania wywoływana jest procedura
obsługi zdarzenia i następnie następuje
przekazanie sterowania.
• Obiekt nasłuchujący musi zarejestrować
się do nasłuchiwania danego typu
zdarzeń w źródle. Ten fakt bezpośrednio
pozwala identyfikować tylko te obiekty
nasłuchujące które jawnie
zadeklarowały się do nasłuchiwania
zdarzeń danego typu z danego źródła.
• Zaletą tego rozwiązania jest również
separacja kodu obsługi (logiki)
przetwarzania zdarzeń oraz logiki
interfejsu generującej te zdarzenia;
• Element interfejsu użytkownika jest w
stanie delegować kod obsługi zdarzeń
do innych fragmentów kodu:
– Jednej wspólnej klasy obsługi zdarzeń
(klasa obsługująca zdarzenia dla grupy
przycisków budowanego GUI);
– Specjalizowanej klasy obsługi kojarzonej z
danym komponentem (klasa specjalizująca
się w obsłudze zdarzeń dla pojedynczego
przycisku);
Delegacyjny model obsługi zdarzeń –
Delegation Event Model
Zdarzenia
• W modelu delegacyjnym zdarzenie
identyfikowane jest jako obiekt
opisujący aktualny stan źródła.
Zdarzenie może być definiowane jako
pewien typ sygnału stanowiący o
zmianie stanu – „coś się stało”;
• Zdarzenie jest obiektem
generowanym przez zewnętrzne
akcje użytkownika takie jak ruchy
myszy, kliknięcia przycisków myszy
oraz klawiatury lub zdarzenia
generowane przez system
operacyjny (timer).
• Komponent GUI na którym
wygenerowane zostało zdarzenie
jest nazywany „źródłem zdarzenia”.
Klasy zdarzeń
AWTEvent
EventObject
AdjustmentEvent
ComponentEvent
TextEvent
ItemEvent
ActionEvent
InputEvent
WindowEvent
MouseEvent
KeyEvent
ContainerEvent
FocusEvent
PaintEvent
ListSelectionEvent
Klasą bazową wszystkich zdarzeń jest
java.util.EventObj
.
Podklasy
EventObj
zajmują się odwzorowaniem
konkretnych typów zdarzeń dla konkretnych
typów komponentów graficznych – akcje
przycisków, zdarzenia okna aplikacji,
specjalizowane zdarzenia komponentów,
zdarzenia myszy i klawiatury.
Akcje użytkownika, źródła
zdarzeń, typy zdarzeń
Źródło
Generowane
Akcja użytkownika
zdarzenia
zdarzenie
Clicked a button
JButton
ActionEvent
Changed text
JTextComponent
TextEvent
Double-clicked on a list item
JList
ActionEvent
Selected or deselected an item
JList
ItemEvent
with a single click
Selected or deselected an item
JComboBox
ItemEvent
Mouse moved or dragged
Component
MouseEvent
Mouse pressed, released,
clicked, entered, or exited
Component
MouseEvent
Window opened, closed
iconified, deiconified, closed
Window
WindowEvent
Click a check box
JCheckBox
ItemEvent,
ActionEvent
Click a radio button
JRadioButton
ItemEvent,
. . .
ActionEvent
Rejestracja do nasłuchu
zdarzenia
Source Object
Trigger an event
Listener Object
Register a listener object
EventObject
Event Handler
Notify listener
Generate
an event
User
action
8
Model delegacji zdarzeń
source: SourceClass
+addXListener(listener: XListener)
listener: ListenerClass
User
Action
Trigger an event
XListener
+
handler(event: XEvent)
Register by invoking
source.addXListener(listener);
(a) A generic source component
with a generic listener
source: JButton
+addActionListener(listener: ActionListener)
listener: CustomListenerClass
ActionListener
+
actionPerformed(event: ActionEvent)
Register by invoking
source.addActionListener(listener);
(b) A JButton source component
with an ActionListener
9
Generyczny model - reprezentacja komponentów
GUI
source: SourceClass
+addXListener(XListener listener)
(a) Internal function of a generic source object
event: XEvent
listener1
listener2
…
listenern
+
handler(
Keep it a list
Invoke
listener1.handler(event)
listener2.handler(event)
…
listenern.handler(event)
An event is
triggered
source: JButton
+addActionListener(ActionListener listener)
(b) Internal function of a JButton object
event:
ActionEvent
listener1
listener2
…
listenern
+
handler(
Keep it a list
Invoke
listener1.actionPerformed(event)
listener2.actionPerformed(event)
…
listenern.actionPerformed(event)
An event is
triggered
Obsługa zdarzeń akcji
Obiekt nasłuchujący musi spełniać następujące
wymagania:
Musi zostać zarejestrowany w przynajmniej jednym
źródle w celu otrzymywania określonych typów
zdarzeń.
Musi implementować metody do odbierania i
przetwarzania danego typu powiadomień.
A listener object must implement the corresponding
listener interface.
Przykład: Klasa nasłuchująca dla klasy JButton musi
implementować interfejs ActionListener. Interfejs
ten zawiera metodę actionPerformed(ActionEvent
e).
Obiekt zdarzenia jest przesyłany do metody obsługi i
zawiera wszystkie potrzebne dane dotyczące źródła
zdarzenia e.getSource() oraz samego zdarzenia.
Wybrane obiekty Listener
Event Class
Listener Interface
Listener Methods (Handlers)
ActionEvent
ActionListener
actionPerformed(ActionEvent e)
ItemEvent
ItemListener
itemStateChanged(ItemEvent e)
WindowEvent
WindowListener
windowClosing(WindowEvent e)
windowOpened(WindowEvent e)
ContainerEvent
ContainerListener
componentAdded(ContainerEvent e)
componentRemoved(ContainerEvent)
MouseEvent
MouseListener
mousePressed(MouseEvent e)
mouseReleased(MouseEvent e)
MouseMotionListener
mouseDraged(MouseEvent e)
mouseMoved(MouseEvent e)
KeyEvent
KeyListener
keyPressed(KeyEvent e)
keyReleased(KeyEvent e)
keyTyped(KeyEvent e)
TexEvent
TextListener
TextValueCnanged(TextEvent e)
Prosty przykład obsługi
zdarzeń
Cel: Wyświetlenie dwóch przycisków w
oknie aplikacji. Wynikiem kliknięcia na
jeden z przycisków ma być komunikat na
ekranie.
1. Utwórz dwa przyciski – źródła
zdarzeń;
2. Dodaj przyciski do okna;
3. Zarejestruj obiekty (obiekt)
nasłuchujący dla dodanych przycisków;
4. Zaimplementuj (nadpisz) obiekt
nasłuchujący.
1. Deklaracja źródeł zdarzeń
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
public class TestActionEvent extends JFrame
implements ActionListener
{
//
1 krok
:
Deklaracja źródeł zdarzeń(2 przyciski)
private JButton jbtOK = new Jbutton(“OK”);
private JButton jbtCL = new Jbutton(“Cancel”);
2. Rejestracja do nasłuchu
// Constructor
public TestActionEvent () {
setTitle();
Container cp = getContentPane();
cp.setLayout(new FlowLayout());
//
2 krok: dodanie źródeł zdarzeń do głównego
okna
cp.add(jbtOK);
cp.add(jbtCL);
//
3 krok: rejestracja obiektu nasłuchującego
;
jbtOK.addActionListener(this);
jbtCL.addActionListener(this);
}
3. Obsługa zdarzeń
//
4 krok: implementacja metody obsługi (handler)
public void actionPerformed(ActionEvent e) {
if(e.getSource() == jbtOK) {
System.out.println(“Wcisnieto przycisk OK”);
}
if(e.getSource() == jbtCL) {
System.out.println(“Wcisnieto przycisk Cancel“);
}// actionPerformed
}
4. Test
public static void main(String[] args) {
TestActionEvent frame = new TestActionEvent();
frame.setDefaultCloseOperation(
JFrame.EXIT_ON_CLOSE);
frame.setSize(100,100);
frame.setVisible(true);
}//main
}// class
Drugi przykład – specjalizowana klasa
obsługi zdarzeń
public class Button2Demo extends JFrame
{
private JButton jbtOK, jbtCL;
ActionListener handler = new ButtonHandler();
public Button2Demo() {
jbtOK = new JButton(“OK”);
jbtOK.addActionListener(handler);
jbtCL = new JButton(“Cancel”);
jbtCL.addActionListener(handler);
}
...
Handling Action Events
...
//
Inner class
class ButtonHandler implements ActionListener {
public void actionPerformed(ActionEvent e)
{
if(e.getSource() == jbtOK) {
System.out.println(“Wcisnieto OK”);
}//if
if(e.getSource() == jbtCL) {
System.out.println(“Wcisnieto Cancel”);
} //if
}// actionPerformed()
}//
Inner class
}// public class
Przykład :
Palindrom
1. Deklaracja komponentów GUI
import Palindrome; // Import class Palindrome
class PalindromeDemo extends JFrame {
// 3 przyciski
private JButton jbtClear, jbtCheck, jbtExit;
// pole tekstowe
private JTextField jtfString;
// etykiety na opis i komunikaty
private JLabel jlResult, jlInstr;
// specjalizowany obiekt obsługi zdarzeń
ActionListener handler = new ButtonHandler();
2. Tworzenie komponentów GUI
public PalindromeDemo() {
// trzy przyciski
jbtCheck = new JButton(“Check”);
jbtClear = new JButton(“Clear”);
jbtExit = new JButton(“Exit”);
// pole tekstowe
jtfString = new JTextField(32);
// etykiety
jlInstr = new JLabel(“Enter phrase to be tested:”);
jlResult = new JLabel(“”);
...
3. Dodanie komponentów do okna,
rejestracja obiektów (obiektu)
nasłuchujących
4a. Implementacja obsługi jako klasy
wewnętrznej
class ButtonHandler implements ActionListener {
public void actionPerformed(ActionEvent e) {
if(e.getSource() == jbtClear) {
jtfString.setText(“”);
jlResult.setText(“”);
}//if
if(e.getSource() == jbtCheck) {
String str = jtfString.getText();
Palindrome pal = new Palindreme(str);
boolean result = pal.IsPalindrome();
if(result) jlResult.setText(“Yes”);
else jlResult.setText(“No”);
} //if
if(e.getSource() == jbtExit) {
System.exit(0);
}
}// actionPerformed()
}// inner class ButtonHandler
Wykorzystanie klasy
Palindrome do weryfikacji.
4b. Implementacja obsługi jako klasy
wewnętrznej
5. Budowa aplikacji – metoda Main
public static void main(String[] args) {
String title = “Is it Palindrome?”;
// Create the frame with UI as an object of
// PalindromeDemo Class.
PalindromeDemo frame = new PalindromeDemo(title);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setsize(400,150);
frame.setVisible(true);
}//main
Klasy anonimowe
Język Java pozwala na definiowanie
klas anonimowych, definiowanych bez
nazwy i konstruktora. Muszą one być
określane w kodzie według
następującej zasady:
new NazwaNadKlasy(arg, arg, ...)
BlokInstrukcji
gdzie:
NazwaNadKlasy jest nazwą nadklasy
definiowanej klasy anonimowej,
arg są argumentami konstruktora
nadklasy (zależnie od podanych
argumentów wywoływany jest
odpowiedni konstruktor nadklasy:
super NazwaNadKlasy(arg, arg, ...) ),
BlokInstrukcji jest blokiem instrukcji
definiujących klasę anonimową.
Przyjmuje się, że w przypadku kiedy
nie ma jawnej definicji nadklasy jest
nią klasa Object
Mariusz Chmielewski
26
Klasy anonimowe
•
Powyższa definicja oznacza stworzenie obiektu klasy anonimowej
dziedziczącej z klasy Contents. Zwracana referencja nowego obiektu klasy
anonimowej jest automatycznie rzutowana na klasę Contents.
Definicja klasy anonimowej jest skrótem następującej definicji:
class MyContents implements Contents {
private int i = 11;
public int value() {
return i;
}
} return new MyContents();
•
W przypadku, gdy klasa anonimowa jest podklasą klasy wewnętrznej,
definicja klasy anonimowej przyjmuje postać:
obiektZewnętrzny.new NazwaNadKlasy(arg, arg, ...) Blok
gdzie:
obiektZewnętrzny - obiekt klasy zewnętrznej zawierającej powtórną
definicję anonimowej klasy wewnętrznej. W tym przypadku wywoływany
jest konstruktor nadklasy: obiektZewnętrzny.new NazwaNadKlasy(arg, arg,
...)
Mariusz Chmielewski
27
Obsługa zdarzeń z wykorzystaniem
klasy anonimowej
// alternatywny sposób definicji klas obsługi
private JButton jbtCheck = new JButton(”Check");
jbtCheck.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
String str = jtfString.getText();
boolean result = isPalindrome(str)
if(result == TRUE)
jlResult.setText(”Yes");
else
jlResult.setText(”No");
}
});
2. Inny sposób obsługi zdarzeń
private JButton jbtClear = new JButton(”Clear");
jbtClear.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
jtfString.setText("");
jlResult.setText("");
}
});
3. Inny sposób obsługi zdarzeń
private JButton jbtExit = new JButton(”Exit");
jbtExit.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
System.exit(0);
}
});