~~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)]]