Uniwersytet Łódzki
Wydział Matematyki i Informatyki, Katedra Analizy Nieliniowej
Swing Java
Wykład 7
Plan wykładu
Co to jest Swing
Swing w NetBeans
Obsługa zdarzeń w Swing
Nasłuchiwacze
Kontrolki Swing
Co to jest Swing
Swing jest częścią Java Foundation Classes (JFC)
Swing zapewnia:
Zbiór kontrolek do tworzenia zaawansowanych GUI: tabele, listy, drzewa, taby, etc …
rozbudowaną funkcjonalność do pracy z tekstem
wsparcie dla wielonarodowości (języki, odpowiedni układ elementów)
look & feels (zaawansowane l’n’f z synth)
Java 2D (Swing został zbudowany na tym pakiecie)
Mechanizm do przywracania i ponawiania operacji (undo & redo)
wsparcie dla osób niepełnosprawnych (lupa, syntezator, wyświetlanie informacji na wyświetlaczu brile’a)
transfer danych: operacja wklej, wytnij, drag&drop
Kontroli w Swing
JButton
JCheckBox
JComboBox
JList
JMenu
JRadioButton
JSlider
JSpinner
JTextField
JPasswordField
Kontrolki z formatowaniem
JColorChooser
JEditorPane
JTextPane
JFileChooser
JTable
JTextArea
JTree
Kontrolki do wyświetlania informacji oraz kontrolki najwyższego poziomu
JLabel
JProgressBar
JSeparator
JToolTip
JPanel
JScrollPane
JSplitPane
JTabbedPane
JToolBar
JInternalFrame
JLayeredPane
RootPane
Swing & Netbeans
Wsparcie IDE przy projektowaniu GUI – automatyczna generacja kodu
Narzędzia do projektowania GUI w Netbeans
Paleta kontrolek
Obszar do projektowania
Okno właściwości
Inspektor
Przykład 1
Event Listner
W celu obsłużenia danego typu zdarzenia należy
zaimplementować odpowiedni typu interfejsu np.
ActionListner
Dana klasa może
implementować wiele nasłuchiwaczy
Każde zdarzenie ma typ i informację o źródle
Generatorami zdarzeń są
przeważnie komponenty bądź modele
event source
event listner
event listner
event listner
event source
event object
event object
Zdarzenia
Zdarzenia powinny być mały obiektami ponieważ obsługiwane są przez główny wątek zajmujący się również rysowaniem
Dłuższe operacje powinny być wykonywane w nowym wątku
Podejścia do implementacji nasłuchwiaczy:
osobna klasa
implementacja jako klasa prywatna
wykorzystanie klasy EventHandler dla prostych zdarzeń
Każde ze zdarzeń dziedziczy z typu EventObject, natomiast jest przeważnie uszczegółowiany np.
(MouseEvent)
Typy zdarzeń
Zdarzenia niskopoziomowe (Low-Level Events)
niskopoziomowe zdarzania w ramach okna oraz wejścia
Przykłady: MouseEvent, KeyEvent
Zdarzenia semantyczne (Semantic Events)
Mogą być odpalane przez wejście użytkownika lub pojawienie się danych
Przykłady: Action i Item
Zaleca się nasłuchiwanie zdarzeń semantyczny niż
niskopoziomowych, gdyż pozwala to na przenaszalność
aplikacji
Interfejsy
Jeden interfejs może mieć więcej niż jedną
metodą. Np. MouseListner zawiera metody:
mousePressed, mouseReleased,
mouseEntered, mouseExit i mouseClick
Zgodnie z założeniami Javy należy
zaimplementować wszystkie funkcje interfejsu, jednak nieużywane mogą mieć puste ciało
Zestaw Interfejsów i Adapterów: http://java.sun.com/docs/books/tutorial/uiswing/events/api.html
Adapter
Każdy nasłuchiwać interfejs może mieć kilka typów adapterów
Adapter implementuje wszystkie metody interfejsu z pustym ciałem
Klas, która ma obsługiwać dany typ zdarzeń dziedziczy po klasie adapter
Wybrane metody należy przeładować
Klasy wewnętrzne i anonimowe klasy wewnętrzne
Problem: wykorzystać adapter ale bez konieczności dziedziczenia przez
klasę publiczną? Np. aplet dziedziczy już po klasie Applet, więc de facto nie może implementować adaptera
Rozwiązanie:
stworzyć klasę wewnętrzną
stworzyć klasę anonimową
Wydajność: szybkość uruchomienia aplikacji oraz wielkość pamięci
zależna od ilości załadowanych klas
Jeśli klasa nie będzie zadeklarowana jako statyczna, ma ona dostęp do pól klasy, w której się znajduje.
public class MyClass extends Applet { ...
cos.addMouseListener(new MyAdapter());
...
class mojAdapter extends MouseAdapter { public void mouseClicked(MouseEvent e) { //implementacja obsługi zdarzenia
} } }
public class MyClass extends Applet { ...
cos.addMouseListener(new MouseAdapter() { public void mouseClicked(MouseEvent e)
{
//implementacja obsługi zdarzenia }
});
...
} }
Klasa EventHandler
Klasa EventHandler wspiera dynamiczne generowanie prostego jednowyrażeniowego nasłuchiwacza zdarzeń
Pozwala uprościć strukturę kodu
Zwiększa wydajność aplikacji – nie potrzeba wczytywać dodatkowych klas (wielokrotna implementacja klasy dla tego samego typu interfejsu)
Wykorzystanie EventHandler
uniemożliwia wykrycie błędu podczas komplikacji. W przypadku błędu w trakcie wykonywania programu rzuci obrzydliwy wyjątek.
Umożliwia rozseparowanie logiki aplikacji od grafiki
//zastosowanie EventHandler
myButton.addActionListener((Act ionListener)EventHandler.cre ate(ActionListener.class, frame, "toFront"));
//zastosowanie klasy wewnetrznej
myButton.addActionListener(new ActionListener() {
public void
actionPerformed(ActionEvent e) {
frame.toFront();
} });
Zastosowania EventHandler
Umożliwia szybki dostęp do właściwości obiektu generatora zdarzeń i ustawienie na docelowym elemencie
//uzycie EventHandler
EventHandler.create(ActionListener.cl ass, myButton, "label",
"source.text")
//uzycie klasy wewnetrznej new ActionListener() { public void
actionPerformed(ActionEvent e) {
myButton.setLabel(((JTextField)e.g etSource()).getText());
} } //uzycie EventHandler
EventHandler.create(ActionListener.c lass, myButton,
"nextFocusableComponent",
"source")
//uzycie klasy wewnetrznej new ActionListener() { public void
actionPerformed(ActionEvent e) {
myButton.setNextFocusableCompone nt((Component)e.getSource());
} }
Umożliwia szybki dostęp do właściwości zdarzenia i ustawia wartość na obiekcie źródłowym
Lista nasłuchiwaczy wspieranych przez wszystkie kompnenty
Component Listener –
nasłuchuje zdarzeń związanych ze zmianą wielkości, widoczności
oraz pozycji komponentu
Focus Listener – sprawdza, czy komponent jest ustawiony fokus
Key Listener – zdarzenia odpalane są tylko przez
komponent, na którym jest fokus
Mouse Listener – nasłuchuje
kliknięcia, przytrzymania klawisza, ruchu myszki wewnątrz lub poza komponent
Mouse-Montion Listener –
nasłuchuje zmian pozycji kursora
Mouse-Wheel Listener – ruch kółka myszki ponad komponentem
Hierarchy Bound Listner –
zmiany w hierarchii zawierania
komponentów dotyczący pozycji
oraz skalowania
Przykładowy nasłuchiwacz: Compnent Listener
Nasłuchuje zdarzeń generowanych przez komponent tj.:
Zmiana pozycji
Zmiana rozmiar
Ukrycie
Adapter Compenent Adapter
Kolejne kroki przy pisaniu Compnent Listner:
Deklaracja klasy implementującej nasłuchiwacz
Wybranie komponentu, który przechwyci zdarzenia
Dodanie nasłuchiwacza do wybranych komponentów
Obsłużenie zdarzeń: Hidden, Shown, Resized, Moved
Przykładowy nasłuchiwacz: Container Listener
Służy do pobierania zdarzeń generowanych na poziomie kontenera
dodanie/usunięcie kontenera
public class ContainerEventDemo implements ContainerListener { ...
przycisk = new JPanel(new GridLayout(1,1));
przycisk.addContainerListener(this);
...
public void componentAdded(ContainerEvent e) { displayMessage(" dodano ", e);
}
public void componentRemoved(ContainerEvent e) { displayMessage(" usunieto ", e); }
void displayMessage(String akcja, ContainerEvent e) {
wyswietlacz.append(((JButton)e.getChild()).getText() +
Przyciski (Buttons)
Przycisk umożliwia:
Wyświetlanie tekstu i obrazów
Przypisanie skrótów (podświetlenie litery w
przycisku – tzw. mnemonic)
Wyświetlanie podpowiedzi (ToolTip)
wyświetlenie tekstu
formatowanego w HTML
Nasłuchiwacze:
Action Listner
Ustawienie standardowego przycisku (setDefaultButton)
//stworzenie przycisku
b1 = new JButton(„Nazwa", Icon);
//ustawienie skrótu
setMnemonic(KeyEvent.VK_M) //ustawnie nazwy akcji
b1.setActionCommand(„akcja") //ustawienie Action Listner b1.addActionListener(this);
//ustawienie podpowiedzi b1.setToolTipText(„porada”) //wylaczenie przycisku b3.setEnabled(false);
//Obsluga zdarzenia
public void actionPerformed(ActionEvent e) { if(„Nazwa".equals(e.getActionCommand())) {
b2.setEnabled(false);
…
Więcej informacji: http://java.sun.com/docs/books/tutorial/uiswing/components/button.html#abstractbutton
Check Boxes & Przycisk Radio
CB stanowi grupę, w której wszystkie, kilka bądź żaden może zostać zaznaczony
JCheckBox i
JCheckBoxMenuItem
dziedziczą z AbstractButton – możliwość umieszczania CB w Menu
Możliwość formatowania CB podobnie jak przycisku
Przycisk Radio – możliwość zaznaczenia wyłączenie jednego przycisku
pierwszyButton = new JCheckBox(„pierwszy");
pierwszyButton.setMnemonic(KeyEvent.VK_P);
//zaznaczanie przycisku
pierwszyButton.setSelected(true);
drugiButton = new JCheckBox(„Drugi");
drugiButton.setMnemonic(KeyEvent.VK_G);
drugiButton.setSelected(true);
//obsluga zdarzen
pierwszyButton.addItemListener(this);
public void itemStateChanged(ItemEvent e) { ...
Object source = e.getItemSelectable();
if (source == pierwszyButton) { //TODO
} else if (source == drugiButton) {
Grupowanie przycisków
Możliwość dodania różnych RB lub CB do wybranej grupy ButtonGroup
Umieszczanie innych rodzajów przycisków poza RB lub CB nie ma sensu, ponieważ nie implementują stanu
włączony/wyłączony
Kroki przy tworzeniu grupy przycisków
Stwórz podklasę JFrame
Wywołaj ContextPane razem z layout manager
Zadeklaruj zbiór przycisków radio
Stwórz obiekt ButtonGroup
Wołaj metodę add na obiekcie buttongroup w celu dodania
każdego przycisku do grupy
Color Chooser
Paleta kolorów z funkcjonalnością wyboru
Paleta składa się z dwóch części:
zestawu kolorów oraz podglądu
CC wykorzystuje
ColorSelectionModel. Model obsługuje RGB, HSB
ColorSelectionModel odpala zdarzenia po każdej zmianie koloru
Pokazywanie CC jako okno dialogowe
Możliwość usunięcia panelu do poglądu, po przez ustawienie panelu bez rozmiaru
cc = new JColorChooser(o.getForeground());
//wykorzystanie ColorSelectionModel
cc.getSelectionModel().addChangeListener(this);
. . .
public void stateChanged(ChangeEvent e) { Color newColor = cc.getColor();
obraz.setForeground(newColor);
}
Color newColor = JColorChooser.showDialog(
ColorChooserDemo2.this, "Choose Background Color", banner.getBackground());
Kontenery najwyższego poziomu
Kontenery najwyższego poziomu (top-level) to: JFrame, JDialog i JApplet
Każde komponent musi przynależeć do hierarchii komponentów. Hierarchia (conatainment hierarchy) jest to drzewo, którego liśćmi są komponenty, a korzeniem kontener najwyższego poziomu.
W przypadku, gdy są trzy top-level kontenery wówczas mamy 3 hierarchie
Każdy kontener najwyższego poziomu zawiera tzw. content pane, do którego dodawane są komponenty
Menu Bar – jest uznawany jako kontener najwyższego poziomu, ale poza content pane
ContentPane ContentPane
MenuBar Kontener
najwyższego poziomu
JFrame
JFrame
JMenuBar
ContentPane JLabel
Dodawanie komponentu
okno.getContentPane().add(
yellowLabel, BorderLayout.CENTER);
Layered Pane
JCompnent
Wszystkie komponenty
Swingowe z „J” dziedziczą po JCompnent. Np. JPanel,
JButton, etc…
JCompnent rozszerza Container, a Container rozszerza Component.
Compnent udostępnia generowanie zdarzeń i rysowanie.
Container umożliwia dodawanie do niego
komponentów i rozkładanie ich
Wszystkie komponenty
Porady - Tool tips – tekst pomocniczy.
Ustawiane za pomocą metody:
setToolTipText
Rysowanie i obramowanie. setBoreder pozwala zdefiniować obramowanie komponentu. Rysowanie realizowane jest w metodzie paintComponent
Look and feel.
Charakterystyczne właściwości.
Możliwość umieszczania dodatkowych informacji put/getClientProperty
Wsparcie dla rozkładu
Wsparcie dla osób niepełnosprawnych
Wsparcie dla drag ‘n’ drop
Podwójne buforowanie
Wsparcie dla klawiatury
Text Component
JTextCompnent
JTextField
JFormattedTextField
JPassworField
Kontrolki tekstowe
JTextField
JFormattedTextField
JPassworField
Formatowane obszary tekstu
JTextField
Obszar tekstu
JTextComponent
JTextComponent udostępnia następującą funkcjonalność:
model document, który zarządza treścią komponentu
view sposób wyświetlania dokumentu na ekranie
sterownik zwany editor kit, który implementuje zdarzenia wykorzystywane przy edycji tekstu
wsparcie dla funkcji cofnij i ponów (undo/redo)
filtry do nawigowania po dokumencie oraz zdarzenia
dla „karetki” (caret)
Dokument
Rozdzielenie widoku od danych
Klasa document implementuje document interfejs
Dokument udostępnia funkcjonalność:
zawiera tekst w elementach, które mogą odnosić się do paragrafu, logicznej struktury
umożliwia edycję po przez wołanie metod remove i insertString
nasłuchiwacze do zmian wprowadzanych w tekście
zarządza obiektem Position, który śledzi pozycję podczas wprowadzania zmian do tekstu
pozwala na uzyskanie informacji o długości tekstu, segmentach tekstu, etc…
Interfejs StyledDocument pozwala na zaznaczanie tekstu
określonym stylem
Nasłuchiwacz dla zmian
Dwa rodzaje nasłuchiwaczy:
dla dokumentu
dla obsługi funkcji cofnij/ponów
Nasłuchiwacza dla zmian w dokumencie odbiera zdarzenia:
wstawiania
usuwania
zmiany stylu tekstu
StyleDocument pozwala na
generowanie wszystkich zdarzeń.
PlainDocument umożliwia
generowanie wyłączenie zdarzeń dotyczących wstawiania/usuwania
doc.addDocumentListener(new MyDocumentListener());
protected class MyDocumentListener implements DocumentListener {
public void insertUpdate(DocumentEvent e) { displayEditInfo(e);
}
public void removeUpdate(DocumentEvent e) { displayEditInfo(e);
}
public void changedUpdate(DocumentEvent e) { displayEditInfo(e);
}
private void displayEditInfo(DocumentEvent e) {
Document document = (Document)e.getDocument();
int changeLength = e.getLength();
changeLog.append(e.getType().toString() + ": "
+ changeLength + " character"
+ ((changeLength == 1) ? ". " : "s. ") + " Text length = " + document.getLength() + "." + newline);
} }