→ Slide 1

Zajęcia 8. - Graficzne interfejsy użytkownika - Swing

→ Slide 2
  • Swing to biblioteka GUI w pakiecie javax.swing
  • Część Java Foundation Classes (JFC)
  • Zbudowany na AWT, ale komponenty Swing są rysowane głównie w Javie (lightweight)
  • Spójny wygląd na różnych systemach operacyjnych
  • Bogatszy zestaw kontrolek niż klasyczne AWT
  • Dokumentacja: javax.swing (Java SE)
→ Slide 3
  • Te same fundamenty: okna, komponenty, kontenery, layouty
  • Ten sam model zdarzeń (listener, event object, źródło zdarzenia)
  • Często używane razem klasy z java.awt (np. BorderLayout, Color, Font)
  • Główne okno nadal opiera się o java.awt.Window (np. JFrame)
→ Slide 4
  • AWT: komponenty natywne (heavyweight), Swing: głównie lekkie komponenty
  • Swing ma osobny model prezentacji (UI delegate, Look & Feel)
  • Swing oferuje więcej gotowych kontrolek i modeli danych
  • W Swing łatwiej utrzymać spójność UI między platformami
  • Rysowanie po komponentach przez paintComponent(Graphics g)
  • W praktyce: nowe GUI desktopowe w Javie zwykle robimy w Swing (lub JavaFX)
→ Slide 5

114_1.jpg

  • ComponentContainerJComponent
  • JComponent to baza większości kontrolek Swing (JButton, JLabel, JTable…)
  • Top-level containers:
    • JFrame - główne okno
    • JDialog - okno dialogowe
    • JWindow - okno bez ramek systemowych
  • Każdy top-level container ma JRootPane z trzema głównymi panelami: glassPane (szklany), layeredPane (warstwowy), contentPane (treści)
→ Slide 6
  • glassPane - przezroczysta warstwa nad wszystkimi panelami (np. do rysowania, obsługi zdarzeń globalnych)
  • layeredPane - warstwy Z-order (kolejność ułożenia komponentów)
  • contentPane - główny obszar, gdzie dodajesz komponenty
  • opcjonalnie menuBar
  • Najczęściej pracujesz z contentPane przez frame.add(…) lub frame.getContentPane().add(…)
JFrame frame = new JFrame("Warstwy Swing");
JComponent glass = (JComponent) frame.getGlassPane();
glass.setVisible(false); // np. true gdy chcemy overlay
 
Container content = frame.getContentPane();
content.setLayout(new BorderLayout());
content.add(new JLabel("Treść główna"), BorderLayout.CENTER);
→ Slide 7
  • Tworzenie GUI uruchamiaj na EDT (Event Dispatch Thread) - wątek odpowiedzialny za obsługę zdarzeń i rysowanie
  • Ustaw setDefaultCloseOperation(…) na JFrame.EXIT_ON_CLOSE, aby zamknąć aplikację po zamknięciu okna
  • pack() - dopasuj rozmiar do zawartości
import javax.swing.*;
import java.awt.*;
 
public class HelloSwing extends JFrame {
    public HelloSwing() {
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        add(new JLabel("Witaj, Swing!", SwingConstants.CENTER), BorderLayout.CENTER);
        pack();
        setLocationRelativeTo(null);
    }
 
    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            HelloSwing frame = new HelloSwing();
            frame.setVisible(true);
        });
    }
}
→ Slide 8
  • Tekst i input: JLabel, JTextField, JTextArea, JPasswordField
  • Wybór: JCheckBox, JRadioButton, JComboBox, JList
  • Akcje: JButton, JToggleButton, JMenuItem, JToolBar
  • Dane złożone: JTable, JTree
  • Kontenery: JPanel, JScrollPane, JTabbedPane, JSplitPane
  • Dialogi: JOptionPane, JFileChooser, JColorChooser
  • JScrollBar, JSeparator, JProgressBar, JSlider, JSpinner, …
→ Slide 9
  • Użytkownik wykonuje akcję na komponencie (źródło zdarzenia)
  • Swing tworzy obiekt zdarzenia (np. ActionEvent)
  • Zarejestrowany listener odbiera callback
JButton btn = new JButton("Policz");
JTextField input = new JTextField(10);
JLabel out = new JLabel("Wynik: -");
 
btn.addActionListener(e -> {
    String text = input.getText().trim();
    out.setText("Wynik: " + text.length());
});
→ Slide 10
  • java.awt.BorderLayout - 5 regionów: NORTH, SOUTH, EAST, WEST, CENTER
  • java.awt.FlowLayout - komponenty od lewej do prawej
  • java.awt.GridLayout - siatka równych komórek
  • java.awt.CardLayout - przełączanie widoków
  • java.awt.GridBagLayout - najbardziej elastyczny (i najbardziej złożony)
  • javax.swing.BoxLayout - pionowo/poziomo
  • javax.swing.SpringLayout - układ sprężynowy
  • javax.swing.GroupLayout - używany przez GUI Designer
→ Slide 11
  • Wtyczka do IntelliJ IDEA do projektowania interfejsów metodą drag-and-drop
  • Definicja UI w pliku .form (XML)
  • Logika aplikacji pozostaje w .java
  • Zalety: szybki prototyp, mniej ręcznego ustawiania layoutów
  • Uwaga: nie edytuj ręcznie .form, jeśli nie musisz
  • Tworzenie aplikacji: Utwórz formę i ustaw setContentPane(panel) wskazując na główny panel z GUI Designer

→ Slide 12
  • Każdy komponent Swing ma delegata UI (np. ButtonUI) odpowiedzialnego za rysowanie i zachowanie
  • Look & Feel (LAF) to zestaw delegatów definiujący styl i zachowanie komponentów
  • Wbudowane LAF: Metal, Nimbus, System
  • LAF ustawiaj przed tworzeniem komponentów
  • Pobranie i ustawienie LAF:
for (UIManager.LookAndFeelInfo info : UIManager.getInstalledLookAndFeels()) {
    if ("Nimbus".equals(info.getName())) {
        UIManager.setLookAndFeel(info.getClassName());
        break;
    }
}
→ Slide 13
  • Action łączy logikę i metadane akcji (tekst, ikona, skrót, enabled)
  • Jedna akcja może być podpięta do wielu komponentów
  • Centralizacja logiki: przycisk, menu, toolbar używają tego samego kodu
  • Parametry: Action.NAME, Action.SHORT_DESCRIPTION, Action.SMALL_ICON, Action.ACCELERATOR_KEY
Action saveAction = new AbstractAction("Zapisz") {
    @Override
    public void actionPerformed(ActionEvent e) {
        System.out.println("Zapis...");
    }
};
saveAction.putValue(Action.SHORT_DESCRIPTION, "Zapisz dane");
 
JButton saveBtn = new JButton(saveAction);
JMenuItem saveItem = new JMenuItem(saveAction);
→ Slide 14
  • Swing był projektowany z myślą o MVC, ale jego komponenty same w sobie są hybrydą View + Controller
  • Przykład: JButton' ma własny ButtonModel' (Model) i własne listenery (Controller), a Ty dostarczasz logikę.
  • Komponenty są powiązane z modelem danych (np. JTable z TableModel), dane trzymasz w modelu, a komponent tylko je wyświetla
→ Slide 15

Dane trzymasz w modelu, a komponent tylko je wyświetla.

Komponent Interfejs modelu Domyślna implementacja Opis
JList ListModel DefaultListModel Lista elementów
JTable TableModel DefaultTableModel Tabela wierszy i kolumn
JComboBox ComboBoxModel DefaultComboBoxModel Lista rozwijana
JTree TreeModel DefaultTreeModel Drzewo węzłów
JTextField, JTextArea Document PlainDocument Treść pola tekstowego
JProgressBar, JSlider, JScrollBar BoundedRangeModel DefaultBoundedRangeModel Wartość w zakresie min–max
JSpinner SpinnerModel SpinnerNumberModel Wartość incrementalna
JButton, JCheckBox, JRadioButton ButtonModel DefaultButtonModel Stan przycisku (wciśnięty, zaznaczony)
↓ Slide 16
DefaultListModel<String> listModel = new DefaultListModel<>();
listModel.addElement("Ala");
listModel.addElement("Ola");
JList<String> list = new JList<>(listModel);
 
DefaultTableModel tableModel = new DefaultTableModel(
    new Object[]{"ID", "Nazwa"}, 0
);
tableModel.addRow(new Object[]{1, "Klient"});
JTable table = new JTable(tableModel);
→ Slide 17

Przykład MVC w Swing

Java Swing MVC Example

* Model — czysta logika i dane (np. stan aplikacji, obliczenia, walidacja) * View — komponenty Swing (JFrame, JPanel, JButton, JTable) * Controller — listenery, które reagują na zdarzenia i wywołują metody modelu

→ Slide 18
  • Swing nie ma natywnego MVVM jak JavaFX, ale można zrobić wariant
  • ViewModel publikuje zmiany przez PropertyChangeSupport
  • View nasłuchuje i aktualizuje kontrolki
class PersonViewModel {
    private final java.beans.PropertyChangeSupport pcs = new java.beans.PropertyChangeSupport(this);
    private String name = "";
 
    public void setName(String newName) {
        String old = this.name;
        this.name = newName;
        pcs.firePropertyChange("name", old, newName);
    }
 
    public void addPropertyChangeListener(java.beans.PropertyChangeListener l) {
        pcs.addPropertyChangeListener(l);
    }
}
→ Slide 19

Utwórz prosty kalkulator wykorzystujący Swing dla języka Java.

Wymagania:

  • Obsługa podstawowych działań: dodawanie, odejmowanie, mnożenie, dzielenie
  • Obsługa liczb niecałkowitych (np. 3.14)
  • Zamiana na liczbę ujemną (±)
  • Czyszczenie (C)
  • Przechowuj aktualną wartość i ostatnią operację, aby umożliwić ciągłe obliczenia
  • Interfejs inspirowany kalkulatorem systemu Windows

Przykładowy wygląd aplikacji:

Kalkulator w Swing - przykładowy interfejs

→ Slide 20