~~NOCACHE~~
~~REVEAL theme=simple&disableLayout=0&transition=none&controls=1&show_progress_bar=1&build_all_lists=0&show_image_borders=0&horizontal_slide_level=2&enlarge_vertical_slide_headers=0&show_slide_details=1&open_in_new_window=1&size=1024x768~~
====== Graficzne interfejsy użytkownika - AWT ======
===== AWT - Abstract Window Toolkit =====
* Pierwsza biblioteka GUI w Javie (pakiet ''java.awt'')
* W dużym stopniu oparta o natywne kontrolki systemowe (//heavy weight//)
* Wygląd i zachowanie komponentów zależy od systemu operacyjnego
* Dziś częściej używa się Swing/JavaFX, ale AWT jest nadal fundamentem modelu zdarzeń i grafiki 2D
* Dokumentacja: [[https://docs.oracle.com/en/java/javase/17/docs/api/java.desktop/java/awt/package-summary.html|java.awt (Java SE 17)]]
===== Hierarchia klas AWT - najważniejsze elementy =====
* ''Component'' - baza dla wizualnych elementów GUI
* ''Container'' - komponent, który może przechowywać inne komponenty
* ''Panel'', ''Window'', ''Frame'', ''Dialog'', ''ScrollPane'' - najczęściej używane kontenery
* Większość aplikacji startuje od ''Frame'' + układ (''LayoutManager'')
===== =====
{{ zajecia:java_2026_1:97_1.jpg |Hierarchia klas AWT}}
===== Component i Container =====
* ''Component'':
* ma pozycję i rozmiar
* może odbierać zdarzenia (mysz, klawiatura)
* może być malowany przez ''paint(Graphics g)''
* ''Container'':
* zarządza dziećmi przez ''add(...)'', ''remove(...)''
* zawiera listę komponentów (i kontenerów)
* zwykle używa menedżera układu (layout)
* po zmianach w strukturze warto wywołać ''validate()'' i ''repaint()''
===== Komponenty AWT - szybki przegląd =====
* ''Button'' - przycisk
* ''Label'' - etykieta tylko do odczytu
* ''TextField'' - jednowierszowe pole tekstowe
* ''TextArea'' - wielowierszowy obszar tekstu
* ''Checkbox'' + ''CheckboxGroup'' - opcje pojedyncze / radio
* ''Choice'' - lista rozwijana
* ''List'' - lista elementów (single/multi selection)
* ''Scrollbar'' - pasek przewijania (poziomy/pionowy)
* ''Canvas'' - obszar do własnego rysowania
===== Kontenery AWT i okna =====
* ''Panel'' - lekki kontener pomocniczy (domyślnie ''FlowLayout'')
* ''Frame'' - główne okno aplikacji (tytuł, ramka, przyciski systemowe, domyślny układ ''BorderLayout'')
* ''Dialog'' - okno pomocnicze (modalne lub niemodalne)
* ''FileDialog'' - systemowy wybór pliku
* ''ScrollPane'' - automatyczne przewijanie pojedynczego komponentu
* ''Applet'' - okno osadzone w przeglądarce (nieużywane)
===== Praca z Frame - minimalny szkielet =====
import java.awt.*;
import java.awt.event.*;
public class MainWindow {
public static void main(String[] args) {
Frame frame = new Frame("AWT - Demo");
frame.setSize(500, 300);
frame.setLayout(new FlowLayout());
frame.add(new Label("Witaj w AWT"));
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
frame.dispose();
System.exit(0);
}
});
frame.setVisible(true);
}
}
===== LayoutManager =====
* Layout oblicza pozycje i rozmiary komponentów
* Bez layoutu (''setLayout(null)'') pozycjonujesz ręcznie: \\ ''setBounds(x, y, width, height)''
* Ręczne pozycjonowanie jest kruche przy zmianie czcionki, DPI i rozmiaru okna
* W praktyce: preferuj layouty i kompozycję wielu paneli (''Panel'')
===== Najczęstsze układy: FlowLayout, BorderLayout, GridLayout =====
* ''FlowLayout'':
* układa komponenty od lewej do prawej, zawija do nowej linii
* ''BorderLayout'':
* regiony: ''NORTH'', ''SOUTH'', ''EAST'', ''WEST'', ''CENTER''
* domyślny układ dla ''Frame''
* ''GridLayout'':
* regularna siatka ''R x C'', wszystkie komórki mają ten sam rozmiar
Panel p = new Panel(new GridLayout(2, 2));
p.add(new Button("A"));
p.add(new Button("B"));
p.add(new Button("C"));
p.add(new Button("D"));
===== Model zdarzeń AWT =====
* Źródło zdarzenia: komponent (np. ''Button'')
* Obiekt zdarzenia: ''ActionEvent'' (naciśnięcie przycisku), ''MouseEvent'' (ruch myszy, kliknięcie), ''KeyEvent'' (naciśnięcie klawisza), ...
* Słuchacz (listener): obiekt implementujący interfejs (np. ''ActionListener'')
* Rejestracja: ''component.addXxxListener(listener)''
Przepływ:
- użytkownik wykonuje akcję (np. kliknięcie przycisku),
- AWT tworzy obiekt zdarzenia (np. ''ActionEvent''),
- zarejestrowany listener otrzymuje callback i wykonuje logikę.
===== Najważniejsze interfejsy listenerów =====
* ''ActionListener'' - kliknięcia przycisków, Enter w ''TextField''
* ''ItemListener'' - zmiana stanu ''Checkbox''/''Choice''
* ''KeyListener'' - zdarzenia klawiatury
* ''MouseListener'' / ''MouseMotionListener'' / ''MouseWheelListener''
* ''WindowListener'' - cykl życia okna (otwarcie, zamknięcie, aktywacja)
* ''FocusListener'', ''ComponentListener'', ''ContainerListener'', ''AdjustmentListener'', ''TextListener''
===== Klasy adapterów - mniej kodu boilerplate =====
* Część listenerów ma wiele metod (np. ''WindowListener'', ''MouseListener'')
* Zamiast implementować wszystkie metody interfejsu, można dziedziczyć po adapterze
* Przykłady: ''WindowAdapter'', ''MouseAdapter'', ''KeyAdapter'', ''FocusAdapter''
frame.addWindowListener(new WindowAdapter() {
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
});
===== Trzy style obsługi zdarzeń =====
- Osobna klasa implementująca listener (najczytelniejsze przy większym kodzie)
- Klasa wewnętrzna (łatwy dostęp do pól klasy zewnętrznej)
- Klasa anonimowa / lambda (krótki kod, gdy logika jest mała)
Button b = new Button("Policz");
TextField tf = new TextField(10);
b.addActionListener(e -> {
String text = tf.getText().trim();
System.out.println("Dane: " + text);
});
===== Rysowanie w AWT: Graphics + Canvas =====
* Do własnego rysowania użyj ''Canvas'' i przeciąż ''paint(Graphics g)''
* [[https://docs.oracle.com/javase/8/docs/api/java/awt/Graphics.html|Graphics]] udostępnia m.in.:
* ''drawLine'', ''drawRect'', ''fillRect'', ''drawOval'', ''fillOval'', ''drawString''
* ''setColor(Color)'', ''setFont(Font)''
* Nie rysuj bezpośrednio "poza" ''paint'' (rysunek zniknie po odświeżeniu)
class DrawingCanvas extends Canvas {
@Override
public void paint(Graphics g) {
g.setColor(Color.BLUE);
g.drawString("AWT Canvas", 20, 30);
g.setColor(Color.RED);
g.fillOval(20, 50, 120, 80);
}
}
===== paint() vs repaint() =====
* ''paint(Graphics g)'' - metoda wywoływana przez system przy odrysowaniu
* ''repaint()'' - zgłoszenie prośby o ponowne odmalowanie
* Zdarzenia myszy/klawiatury zwykle aktualizują stan modelu i wywołują ''repaint()''
* Dobrą praktyką jest trzymanie danych rysunku w polach klasy, a nie w obiekcie ''Graphics''
===== Dobre praktyki i typowe pułapki =====
* Zamykanie okna: zawsze obsłuż ''windowClosing''
* Nie blokuj głównego wątku (obsługa zdarzeń) długimi pętlami - użyj wątku roboczego
* Używaj layoutów zamiast stałych współrzędnych
* Po zmianie stanu modelu GUI: ''repaint()''; po przebudowie komponentów: ''validate()''
* AWT i Swing można mieszać ale ostrożnie - lepiej trzymać się jednego frameworka
===== Ćwiczenia praktyczne =====
* "Witaj świecie" - proste okno z etykietą
* Utwórz okno ''Frame'' z tytułem "Witaj AWT" i dodaj do niego ''Label'' z tekstem "Witaj, świecie!".
* Obsłuż zdarzenie zamknięcia przez implementację interfejsu '' WindowListener''
* Formularz z polami tekstowymi (''TextField'') pobierającymi dane (np. imie i nazwisko) i przyciskiem ''Button'' do wyświetlania powitania w ''Label''.
* Klasa okna głównego dziedziczy po ''Frame''
* Obsłuż zdarzenie kliknięcia przycisku (''ActionListener'') i wyświetl powitanie w ''Label'' (np. "Witaj, Jan Kowalski")
* Obsłuż zdarzenie naciśnięcia klawisza Enter w polu tekstowym, aby również wyświetlić powitanie (poprzez wywołanie akcji przycisku)
* Użyj ''BorderLayout'' i ''Panel'' do rozmieszczenia komponentów
* Obsługa zamknięcia okna za pomocą ''WindowAdapter''.
* Rysowanie w oknie:
* Utwórz klasę dziedziczącą po ''Frame'' lub ''Canvas'' do rysowania
* Przeciąż metodę ''paint(Graphics g)'' i narysuj kilka kształtów (linie, prostokąty, elipsy).
* Dodaj obsługę zdarzeń myszy, aby rysować po ''Canvas'' wciśnięciu i przeciąganiu myszy (''MouseMotionListener'').
* Dodaj przycisk "Wyczyść", który czyści rysunek
* Narysuj tekst na ekranie za pomocą ''drawString()'' zawierający aktualne współrzędne myszy. Dobierz font, wielkość i kolor tekstu.
* Dodaj podwójne buforowanie, aby uniknąć migotania podczas rysowania (''createImage()'', ''getGraphics()'').
* Przegląd kontrolek: zapoznaj się z kodem źródłowym i przetestuj działanie programu
===== Zadanie 6: Minutnik w AWT =====
Stwórz w bibliotece AWT prostą aplikację typu **minutnik**, która odlicza czas od wartości podanej przez użytkownika do **0**.
Wymagania:
* Użytkownik wprowadza wartość początkową czasu w sekundach w ''TextField''. Domyślnie może być ustawiona na 60 sekund.
* Aplikacja posiada przyciski:
* "Start" - rozpoczyna lub wznawia odliczanie,
* "Stop" - zatrzymuje odliczanie,
* "Reset" - przywraca licznik do wartości początkowej.
* Po zakończeniu odliczania (osiągnięciu 0) aplikacja wyraźnie informuje użytkownika, np. zmianą koloru tła okna,
lub wyświetleniem komunikatu w oknie dialogowym.
* Zaimplementuj odliczanie z użyciem **wątku** (tak, aby interfejs GUI nie zawieszał się podczas pracy minutnika).
* Zapewnij poprawne zamykanie aplikacji (obsługa zdarzenia zamknięcia okna).
* Przyciski powinny być aktywne/nieaktywne w zależności od stanu minutnika (np. "Start" nieaktywny podczas odliczania, "Stop" nieaktywny gdy minutnik jest zatrzymany).
Przykładowy wygląd aplikacji:
{{ zajecia:java_2026_1:minutnik.png?300 |Minutnik AWT - przykładowy interfejs}}
===== Materiały dodatkowe =====
* [[https://docs.oracle.com/en/java/javase/17/docs/api/java.desktop/java/awt/package-summary.html|java.awt (Java SE 17)]]
* [[https://docs.oracle.com/en/java/javase/17/docs/api/java.desktop/java/awt/event/package-summary.html|java.awt.event (Java SE 17)]]
* [[https://docs.oracle.com/en/java/javase/17/docs/api/java.desktop/java/awt/Component.html|java.awt.Component (Java SE 17)]]
* [[https://docs.oracle.com/en/java/javase/17/docs/api/java.desktop/java/awt/Container.html|java.awt.Container (Java SE 17)]]
* [[https://docs.oracle.com/en/java/javase/17/docs/api/java.desktop/java/awt/Graphics.html|java.awt.Graphics (Java SE 17)]]