===== Zadania praktyczne i samodzielne ===== ==== Zadanie 5.2 z zajęć PA ===== Wykorzystując bibliotekę AWT stwórz prosty minutnik, który pozwala na odliczanie czasu od wartości podanej przez użytkownika do 0. Po zakonczeniu odliczania poinformuj o tym użytkownika (np. zmieniając kolor tła okna lub wyświetlając widoczną informację). Aplikacja powinna posiadać możliwość uruchomienia odliczania, zatrzymania go, ponownego uruchomienia i powrotu do stanu pierwotnego licznika. W swoim kodzie postaraj się wykorzystać wątki. ==== Demo 1 (10-15 min): Mini-formularz ==== Cel: przećwiczyć ''Frame'', ''Panel'', ''TextField'', ''Button'', ''ActionListener''. Kroki: - utwórz ''Frame'' z ''BorderLayout'' - dodaj dwa pola ''TextField'' (imię, nazwisko) - dodaj przycisk ''Pokaż'' - po kliknięciu wyświetl ''Label'': "Witaj, Imię Nazwisko" Wskazówki: * logikę przycisku zapisz jako lambda * przypnij ''WindowAdapter'', by poprawnie zamknąć aplikację Skrócone rozwiązanie: showButton.addActionListener(e -> { resultLabel.setText("Witaj, " + nameTf.getText() + " " + surnameTf.getText()); }); ==== Demo 2 (10-15 min): Canvas - rysowanie i czyszczenie ==== Cel: przećwiczyć ''Canvas'', ''paint()'', ''repaint()'', ''MouseMotionListener''. Kroki: - przygotuj klasę ''PaintCanvas'' przechowującą listę punktów - w ''mouseDragged'' dodawaj punkt i wywołuj ''repaint()'' - dodaj przycisk ''Wyczyść'', który resetuje listę punktów Wskazówki: * nie rysuj bezpośrednio w listenerze * ''paint'' ma tylko odtwarzać stan zapisany w polach klasy Skrócone rozwiązanie: clearButton.addActionListener(e -> canvas.clearAll()); ==== Demo 3 (opcjonalne): Zmiana layoutu w runtime ==== Cel: pokazać różnicę między ''FlowLayout'' i ''GridLayout''. Kroki: - utwórz panel z 6 przyciskami - przełączaj layout przyciskiem ''Przełącz układ'' - po zmianie wykonaj ''panel.validate()'' i ''panel.repaint()'' ==== Zadania samodzielne - poziom podstawowy ==== - Zadanie A1: Kalkulator sumy * Dwa pola ''TextField'' + przycisk ''Oblicz'' + ''Label'' z wynikiem * Obsłuż błędne dane (''NumberFormatException'') i pokaż komunikat - Zadanie A2: Licznik kliknięć * Przycisk ''Kliknij mnie'' zwiększa licznik i odświeża ''Label'' - Zadanie A3: Formularz wyboru * ''CheckboxGroup'' (np. "Tryb A / Tryb B") i ''Choice'' z 3 opcjami * Po zmianie wyboru aktualizuj etykietę podsumowującą ==== Zadania samodzielne - poziom średni ==== - Zadanie B1: Notatnik mini * ''TextArea'' + przyciski ''Wyczyść'' i ''Statystyki'' * ''Statystyki'' pokazują liczbę znaków i linii - Zadanie B2: Prosty rysownik figur * Na ''Canvas'' rysuj kliknięciem koło lub prostokąt (wybór przez ''Choice'') * Dodaj zmianę koloru figur (np. ''Checkbox'' lub ''Choice'') - Zadanie B3: Okno "Ustawienia" * Główne okno ''Frame'' + ''Dialog'' niemodalny * W dialogu użytkownik zmienia rozmiar czcionki etykiety w głównym oknie ==== Zadania samodzielne - poziom zaawansowany ==== - Zadanie C1: Prosty program do rysowania * Rysowanie na formie lub ''Canvas'' przy wciśniętym klawiszu myszy. Rejestruj kolejne punkty w odpowiedniej strukturze danych tak aby można było je później odtworzyć. * Dodaj możliwość wyboru koloru i grubości linii * Dodaj przycisk "Wyczyść" do usuwania rysunku * Dodaj przycisk "Zapisz" do zapisywania rysunku do pliku (np. jako obraz PNG) * Dodaj przycisk "Animuj", który odtwarza sekwencję rysowania (odtwarzanie kolejnych punktów z opóźnieniem) w osobnym wątku. Zatrzymanie animacji powinno być możliwe po ponownym kliknięciu "Animuj". - Zadanie C2: Animacja w AWT * Obiekt (kula/prostokąt) porusza się po ''Canvas'' i odbija od krawędzi * Aktualizacja położenia w osobnym wątku + ''repaint()'' - Zadanie C3: Mini-gra "reakcja" * Co losowy czas pojawia się cel; użytkownik klika jak najszybciej * Mierz czas reakcji i wyświetl średnią z ostatnich N prób ==== Podpowiedzi i szkice rozwiązań do zadań samodzielnych ==== * A1 (Kalkulator sumy): * Podpowiedź: parsuj przez ''Integer.parseInt(...)'' w ''try/catch'' * Szkic rozwiązania: try { int a = Integer.parseInt(aField.getText().trim()); int b = Integer.parseInt(bField.getText().trim()); result.setText("Suma: " + (a + b)); } catch (NumberFormatException ex) { result.setText("Błąd: podaj poprawne liczby całkowite"); } * A2 (Licznik kliknięć): * Podpowiedź: licznik trzymaj w polu klasy, nie w zmiennej lokalnej callbacka * Szkic rozwiązania: ''counter++; label.setText("Kliknięcia: " + counter);'' * B1 (Notatnik mini): * Podpowiedź: liczba linii = ''textArea.getText().split("\\R", -1).length'' * Szkic rozwiązania: po kliknięciu ''Statystyki'' pokaż wynik w ''Label'' lub ''Dialog'' * B2 (Rysownik figur): * Podpowiedź: przechowuj listę obiektów ''ShapeModel'' (typ, x, y, kolor) * Szkic rozwiązania: w ''paint'' iteruj po liście i rysuj odpowiednią figurę * C2 (Animacja): * Podpowiedź: osobny wątek aktualizuje pozycję co 16-25 ms, UI tylko odmalowuje * Szkic rozwiązania: new Thread(() -> { while (running) { x += vx; y += vy; if (x < 0 || x > getWidth() - size) vx = -vx; if (y < 0 || y > getHeight() - size) vy = -vy; repaint(); try { Thread.sleep(16); } catch (InterruptedException ignored) {} } }).start(); ==== Wskazówki do zadań i kryteria oceny ==== * Minimalne wymagania: * poprawna obsługa zamknięcia okna * sensowny layout (bez ''setLayout(null)'') * działająca obsługa zdarzeń * Dodatkowe punkty: * walidacja danych wejściowych * czytelny podział kodu na klasy * użycie adapterów tam, gdzie mają sens * brak "zawieszania" GUI