====== Zajecia 9. - JavaFX - zadania do samodzielnego wykonania ======
===== Organizacja =====
* Czas: 20-30 min
* Forma: samodzielnie lub w parach
* Zakres: od prostych kontrolek po mini-aplikacje z FXML i CSS
===== Zadanie A (latwe): Konwerter temperatur =====
Wymagania:
* Pole wejscia temperatury
* Dwa przyciski: ''C -> F'' i ''F -> C''
* Etykieta z wynikiem
Wskazowki:
* Uzyj ''Double.parseDouble''
* Obsluz ''NumberFormatException''
* Obliczenia: ''F = C * 9 / 5 + 32'' oraz ''C = (F - 32) * 5 / 9''
Rozwiazanie (przykladowe):
btnCtoF.setOnAction(e -> {
try {
double c = Double.parseDouble(input.getText().trim());
result.setText(String.format("%.2f F", c * 9 / 5 + 32));
} catch (NumberFormatException ex) {
result.setText("Blad danych");
}
});
btnFtoC.setOnAction(e -> {
try {
double f = Double.parseDouble(input.getText().trim());
result.setText(String.format("%.2f C", (f - 32) * 5 / 9));
} catch (NumberFormatException ex) {
result.setText("Blad danych");
}
});
===== Zadanie B (srednie): Formularz studenta =====
Wymagania:
* Pola: imie, nazwisko, numer indeksu
* ''ComboBox'' z kierunkiem studiow
* Przycisk ''Zapisz'' wyswietla podsumowanie w ''TextArea''
Wskazowki:
* Uzyj ''GridPane'' do ukladu formularza
* Waliduj, czy pola tekstowe nie sa puste
* Przed zapisem wyczysc ''TextArea'' i wpisz podsumowanie
Rozwiazanie (przykladowe):
saveBtn.setOnAction(e -> {
String first = firstName.getText().trim();
String last = lastName.getText().trim();
String index = indexField.getText().trim();
String major = majorBox.getValue();
if (first.isEmpty() || last.isEmpty() || index.isEmpty() || major == null) {
summary.setText("Uzupelnij wszystkie pola");
return;
}
summary.setText(
"Student:\n" +
"Imie: " + first + "\n" +
"Nazwisko: " + last + "\n" +
"Indeks: " + index + "\n" +
"Kierunek: " + major
);
});
===== Zadanie C (srednie+): Lista wydatkow =====
Wymagania:
* ''TableView'' z kolumnami: nazwa, kategoria, kwota
* Dodawanie nowego wydatku przez formularz
* Etykieta sumy wszystkich wydatkow
Wskazowki:
* Model danych jako klasa ''Expense'' z ''StringProperty'' i ''DoubleProperty''
* Po dodaniu rekordu aktualizuj etykiete sumy
* Uzyj ''PropertyValueFactory'' albo bindingu kolumn
Rozwiazanie (przykladowe):
private final ObservableList expenses = FXCollections.observableArrayList();
private void updateTotal() {
double total = expenses.stream().mapToDouble(Expense::getAmount).sum();
totalLabel.setText(String.format("Suma: %.2f PLN", total));
}
addBtn.setOnAction(e -> {
try {
Expense expense = new Expense(
nameField.getText().trim(),
categoryBox.getValue(),
Double.parseDouble(amountField.getText().trim())
);
expenses.add(expense);
updateTotal();
} catch (Exception ex) {
totalLabel.setText("Blad: sprawdz dane");
}
});
===== Zadanie D (trudniejsze): Logowanie w FXML + CSS + walidacja =====
Wymagania:
* Widok w FXML (email, haslo, przycisk, status)
* Kontroler z walidacja danych
* Stylowanie przez zewnetrzny plik CSS
* Przycisk aktywny tylko dla poprawnych danych
Wskazowki:
* ''fx:id'' mapuj na pola ''@FXML''
* Aktywacje przycisku zrob przez binding ''disableProperty''
* Reguly: email zawiera ''@'' i ''.'', haslo minimum 8 znakow
Rozwiazanie (przykladowe):
loginBtn.disableProperty().bind(
Bindings.createBooleanBinding(
() -> {
String email = emailField.getText().trim();
String pass = passwordField.getText();
return !(email.contains("@") && email.contains(".") && pass.length() >= 8);
},
emailField.textProperty(),
passwordField.textProperty()
)
);
loginBtn.setOnAction(e -> statusLabel.setText("Dane poprawne - logowanie..."));
===== Zadanie E (dla chetnych): Mini klient RIA =====
Wymagania:
* Widok JavaFX pobiera dane JSON z lokalnego endpointu REST
* Wyswietlenie listy rekordow (np. studenci) w ''ListView'' lub ''TableView''
* Obsluga bledu polaczenia
Wskazowki:
* Uzyj ''HttpClient'' i ''Task'' (nie blokuj watku UI)
* Wynik wrzuc do UI przez ''Platform.runLater(...)''
* Przygotuj fallback: komunikat o bledzie i pusta lista
Rozwiazanie (szkic):
Task loadTask = new Task<>() {
@Override
protected String call() throws Exception {
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("http://localhost:8080/api/students"))
.GET()
.build();
return HttpClient.newHttpClient()
.send(request, HttpResponse.BodyHandlers.ofString())
.body();
}
};
loadTask.setOnSucceeded(e -> statusLabel.setText("Pobrano dane"));
loadTask.setOnFailed(e -> statusLabel.setText("Blad polaczenia"));
new Thread(loadTask).start();
===== Kryteria oceny wykonania =====
* Dzialajacy interfejs i reakcja na zdarzenia
* Poprawna walidacja danych i obsluga bledow
* Czytelny podzial kodu (UI, logika, model)
* Dla wyzszej oceny: FXML + CSS + binding + dobra struktura projektu