PO Graficzny interfejs użytkownika - ćwiczenia

From Studia Informatyczne

<<< Powrót do przedmiotu Programowanie obiektowe

<<< Powrót do wykładu Graficzny interfejs użytkownika

Spis treści

Zadanie 1

W klasie WitajŚwiecie umieść w oknie głównym drugą etykietę z tekstem. Użyj w tym celu bezparametrowej metody add(). Czemu obie etykiety nie są widoczne?

Podgląd działającego rozwiązania
Archiwum JAR Applet
Żeby uruchomić przykład Po_GUI_Zad1.jar ściągnij najpierw archiwum jar na swój komputer (możesz to zrobić klikając na odnośniku prawym klawiszem myszy i wybierając "Zapisz jako...") i uruchom jak zwykły program.

Rozwiązanie kod

import javax.swing.*;

public class Zad1 {
  private static void utwórzGUI() {
    //tworzenie nowego okna 
    JFrame frame = new JFrame("Okno Zad1");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
   //dodawanie etykiety z przywitaniem
   JLabel label1 = new JLabel("Witaj świecie");
   JLabel label2 = new JLabel("Jestem drugą etykietą");
   frame.add(label1);
   frame.add(label2);
    
    //ustalanie wymiarów i wyświetlanie okna
    //frame.pack();
    frame.setSize(300,150);
    frame.setVisible(true);
  }
  
  public static void main(String[] args) {
    //aby uniknąć zakleszczeń, tworzenie GUI zawsze zlecamy dla wątku obsługi zdarzeń
    SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        utwórzGUI();
      }
    });
  }
}

Rozwiązanie wyjaśnienie

Widoczna będzie tylko etykieta dodana jako ostatnia, gdyż w każdym rejonie (bezparametrowa metoda add() dodaje komponenty po środku) może znajdować się tylko jeden komponent. Kolejne dodawane komponenty zastępują poprzednie.

Zadanie 2

Zmodyfikuj klasę GridLayoutTest, tak aby to trzecia (tam gdzie jest przycisk P3), a nie szósta pozycja w siatce była pusta.

Podgląd działającego rozwiązania
Archiwum JAR Applet
Żeby uruchomić przykład Po_GUI_Zad2.jar ściągnij najpierw archiwum jar na swój komputer (możesz to zrobić klikając na odnośniku prawym klawiszem myszy i wybierając "Zapisz jako...") i uruchom jak zwykły program.

Rozwiązanie kod

import java.awt.*;
import javax.swing.*;

public class Zad2 extends JFrame {
  Zad2() {
    super("Okno Zad2");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
    setLayout(new GridLayout(3,2));
    add(new JButton("P1"));
    add(new JButton("P2"));
    add(new JPanel());//pusty JPanel symuluje puste miejsce
    add(new JButton("P3"));
    add(new JButton("P4"));
    add(new JButton("Bardzo długi przycisk"));
    setSize(300,150);
    setVisible(true);
  }
 
  public static void main(String[] args) {
    //aby uniknąć zakleszczeń, tworzenie GUI zawsze zlecamy dla wątku obsługi zdarzeń
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        new Zad2();
      }
    });
  }
}

Zadanie 3

Wyświetl okno o rozmiarach 300 na 150, zawierające na górze pięć przycisków: P1, P2, P3, P4 i Bardzo długi przycisk rozmieszczonych przez GridLayout o dwóch wierszach i trzech kolumnach, a na dole takie same pięć przycisków rozmieszczonych przy pomocy FlowLayout. Grupy przycisków powinny być rozmieszczone na oknie przez BorderLayout. Sprawdź, czy wszystkie przyciski mieszczą się w oknie o tych rozmiarach.

Podgląd działającego rozwiązania
Archiwum JAR Applet
Żeby uruchomić przykład Po_GUI_Zad3.jar ściągnij najpierw archiwum jar na swój komputer (możesz to zrobić klikając na odnośniku prawym klawiszem myszy i wybierając "Zapisz jako...") i uruchom jak zwykły program.

Rozwiązanie kod

import java.awt.*;
import javax.swing.*;

public class Zad3 extends JFrame {
  JPanel panel1, panel2;
  
  Zad3() {
    super("Okno Zad3");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
    panel1 = new JPanel();
    panel1.setLayout(new GridLayout(2,3));
    panel1.add(new JButton("P1"));
    panel1.add(new JButton("P2"));
    panel1.add(new JButton("P3"));
    panel1.add(new JButton("P4"));
    panel1.add(new JButton("Bardzo długi przycisk"));
    
    panel2 = new JPanel();
    //Obiekty JPanel domyślnie używają FlowLayout.
    panel2.add(new JButton("P1"));
    panel2.add(new JButton("P2"));
    panel2.add(new JButton("P3"));
    panel2.add(new JButton("P4"));
    panel2.add(new JButton("Bardzo długi przycisk"));

    //Główne kontenery (JApplet, JDialog i JFrame) domyślnie używają BorderLayout.
    add(BorderLayout.NORTH, panel1);
    add(BorderLayout.SOUTH, panel2);

    setSize(300,150);
    setVisible(true);
  }
 
  public static void main(String[] args) {
    //aby uniknąć zakleszczeń, tworzenie GUI zawsze zlecamy dla wątku obsługi zdarzeń
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        new Zad3();
      }
    });
  }
}

Zadanie 4

Używając BoxLayout i obiektów klasy Box przygotuj program wyświetlający 5 przycisków rozmieszczonych w dwóch kolumnach (w pierwszej trzy w drugiej dwa). Niech w każdej kolumnie przyciski będą wyśrodkowane. Porównaj efekt z przykładem GridLayoutTest.

Podgląd działającego rozwiązania
Archiwum JAR Applet
Żeby uruchomić przykład Po_GUI_Zad4.jar ściągnij najpierw archiwum jar na swój komputer (możesz to zrobić klikając na odnośniku prawym klawiszem myszy i wybierając "Zapisz jako...") i uruchom jak zwykły program.

Wskazówka 1

Jako pierwszy parametr konstruktora trzeba przekazać obiekt ContentPane, a nie kontener. Obiekt ContentPane dla danego kontenera uzyskuje się przy pomocy metody getContentPane().

Wskazówka 2

BoxLayout respektuje sposób wyśrodkowania preferowany przez komponenty. Do zmiany preferowanego wyśrodkowania komponentu służy metoda setAlignmentX(Component.CENTER_ALIGNMENT).

Rozwiązanie kod

import java.awt.*;
import javax.swing.*;

public class Zad4 extends JFrame {
  Box box1, box2;
 
  void dodajPrzycisk(Box box, JButton p) {
    //BoxLayout respektuje sposób wyśrodkowania preferowany przez komponenty
    p.setAlignmentX(Component.CENTER_ALIGNMENT);
    box.add(p);
  }
  
  Zad4() {
    super("Okno Zad4");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
 
    box1 = new Box(BoxLayout.Y_AXIS);
    dodajPrzycisk(box1, new JButton("P1"));
    dodajPrzycisk(box1, new JButton("P3"));
    dodajPrzycisk(box1, new JButton("Bardzo długi przycisk"));

    box2 = new Box(BoxLayout.Y_AXIS);
    dodajPrzycisk(box2, new JButton("P2"));
    dodajPrzycisk(box2, new JButton("P4"));

    //jako pierwszy parametr konstruktora trzeba przekazać obiekt ContentPane, a nie kontener
    setLayout(new BoxLayout(this.getContentPane(), BoxLayout.X_AXIS));
    add(box1);
    add(box2);
    
    setSize(300,150);
    setVisible(true);
  }
  
  public static void main(String[] args) {
    //aby uniknąć zakleszczeń, tworzenie GUI zawsze zlecamy dla wątku obsługi zdarzeń
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        new Zad4();
      }
    });
  }
}

Zadanie 5

Przygotuj program wyświetlający przycisk, który po najechaniu na niego myszką zmienia położenie. Do zmiany położenia użyj CardLayout.

Podgląd działającego rozwiązania
Archiwum JAR Applet
Żeby uruchomić przykład Po_GUI_Zad5.jar ściągnij najpierw archiwum jar na swój komputer (możesz to zrobić klikając na odnośniku prawym klawiszem myszy i wybierając "Zapisz jako...") i uruchom jak zwykły program.

Wskazówka 1

Dodaj do przycisków MouseListener, a kod zamieniający kartki umieść w metodzie mouseEntered(MouseEvent)

Wskazówka 2

Jeżeli używasz CardLayout w głównym kontenerze, jako parametr parent metod first(), last(), next() i previous() przekazuj kontener uzyskany z głównego kontenera przy pomocy metody getContentPane(), a nie sam główny kontener.

Rozwiązanie kod

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class Zad5 extends JFrame {
  Box box1, box2;
  JButton p1, p2;
  CardLayout karty;
  JFrame okno;
  //obiekty klasy wewnętrznej mogę korzystać ze składowych obiektu, który je utworzył
  class ZamianaKart extends MouseAdapter {
    public void mouseEntered(MouseEvent e) {
     //jeżeli używasz CardLayout w głównym kontenerze, to metodom oczekującym parametru
     //opisanego w dokumentacji jako "the parent container in which to do the layout"
     //przekazuj kontener uzyskany z głównego kontenera przy pomocy metody getContentPane(),
     //a nie sam główny kontener
     karty.next(okno.getContentPane());
    }
  }
 
  Zad5() {
    super("Okno Zad5");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    okno = this;
   
    box1 = new Box(BoxLayout.X_AXIS);
    box1.add(Box.createRigidArea(new Dimension(50,0)));
    p1 = new JButton("Kliknij");
    p1.addMouseListener(new ZamianaKart());
    box1.add(p1);

    box2 = new Box(BoxLayout.X_AXIS);
    box2.add(Box.createRigidArea(new Dimension(170,0)));
    p2 = new JButton("Kliknij");
    p2.addMouseListener(new ZamianaKart());
    box2.add(p2);

    karty = new CardLayout();
    setLayout(karty);
    //okno.setLayout(new GridLayout(2,2));
    add(box1, "lewo");
    add(box2, "prawo");
   
    setSize(300,150);
    setVisible(true);
  }
 
  public static void main(String[] args) {
    //aby uniknąć zakleszczeń, tworzenie GUI zawsze zlecamy dla wątku obsługi zdarzeń
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        new Zad5();
      }
    });
  }
}

Zadanie 6

Rozszerz klasę Dodawanie o możliwość zmiany działania na mnożenie. Niech wybór działania będzie możliwy przy pomocy przycisku combo (JComboBox). Niech wynik będzie obliczany zarówno gdy zostanie zaakceptowana wartość z któregoś z pól, oraz gdy zostanie zmienione działanie. Niech zawartość pól tekstowych będzie wyśrodkowana do prawej.

Podgląd działającego rozwiązania
Archiwum JAR Applet
Żeby uruchomić przykład Po_GUI_Zad6.jar ściągnij najpierw archiwum jar na swój komputer (możesz to zrobić klikając na odnośniku prawym klawiszem myszy i wybierając "Zapisz jako...") i uruchom jak zwykły program.

Rozwiązanie kod

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

public class Zad6 extends JFrame {
  JFrame okno = this;
  JTextField wynik = new JTextField(9);
  JTextField pole1 = new JTextField("1",9);
  JTextField pole2 = new JTextField("2",9);
  JComboBox działanie = new JComboBox();
 
  public void licz() {
    try {
      String dz = (String) działanie.getSelectedItem();
      Integer w;
      if (dz.equals("+"))
        w = Integer.parseInt(pole1.getText()) + Integer.parseInt(pole2.getText());
      else
        w = Integer.parseInt(pole1.getText()) * Integer.parseInt(pole2.getText());
      wynik.setText(w.toString());
    } catch (NumberFormatException ex) {
      wynik.setText("Błąd");
    }
  }
 
  //do obsługi zdarzeń często używane są anonimowe klasy wewnętrzne
  //jeden egzemplarz będzie dzielony przez oba pola
  ActionListener sumowanie = new ActionListener() {
    public void actionPerformed(ActionEvent ev) {
      licz();
    }
  };
 
  Zad6() {
    super("Okno ZliczanieKliknięć");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JPanel panel = new JPanel();
    panel.setLayout(new FlowLayout());

    panel.add(pole1);
    pole1.addActionListener(sumowanie);
    pole1.setHorizontalAlignment(JTextField.RIGHT);

    działanie.addItem("+");
    działanie.addItem("*");
    działanie.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        licz();
      }
    });
    panel.add(działanie);
    
    panel.add(pole2);
    pole2.addActionListener(sumowanie);
    pole2.setHorizontalAlignment(JTextField.RIGHT);

    panel.add(new JLabel("="));
    wynik.setEditable(false);
    panel.add(wynik);
   
    //puste obramowanie odsuwa komponenty od krawędzi
    panel.setBorder(BorderFactory.createEmptyBorder(30,15,30,15));
    add(panel);
   
    setSize(300,150);
    setVisible(true);
  }
 
  public static void main(String[] args) {
    //aby uniknąć zakleszczeń, tworzenie GUI zawsze zlecamy dla wątku obsługi zdarzeń
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        new Zad6();
      }
    });
  }
}

Zadanie 7

Komponenty Swing wyświetlające tekst obsługują formatowanie HTML. Korzystając z tego udogodnienia, stwórz prostą aplikację wyświetlającą stronę HTML znajdującą się pod zadanym adresem URL. Do wyświetlania strony użyj obiektu JEditorPane. Do odczytywania strony użyj obiektu java.net.URL.

Podgląd działającego rozwiązania
Archiwum JAR Applet
Żeby uruchomić przykład Po_GUI_Zad7.jar ściągnij najpierw archiwum jar na swój komputer (możesz to zrobić klikając na odnośniku prawym klawiszem myszy i wybierając "Zapisz jako...") i uruchom jak zwykły program.

Wskazówka 1

Metoda setPage(URL) nie usuwa wszystkich informacji o poprzednio wyświetlanej stronie, np. definicji stylów. Aby pozbyć się wszystkich pozostałości należy utworzyć nowy dokument przy pomocy wywołania getEditorKit().createDefaultDocument() i przekazać go do metody setDocument().

Rozwiązanie kod

import java.awt.*;
import java.awt.event.*;

import javax.swing.*;

public class Zad7 extends JFrame {
  JEditorPane tekst = new JEditorPane();
  JTextField adres = new JTextField("http://www.google.pl"); 
  JButton przycisk = new JButton("Wczytaj stronę");
 
  Zad7() {
    super("Okno ZliczanieKliknięć");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
   
    ActionListener wczytajStronę = new ActionListener() {
      public void actionPerformed(ActionEvent ev) {
        java.net.URL url = null;
        try {
          //poprzedni dokument mógł pozostawić style
          tekst.setDocument(tekst.getEditorKit().createDefaultDocument());          
          url = new java.net.URL(adres.getText());
          tekst.setPage(url);
        } catch (Exception e) {
          System.err.println("Błędny URL: " + url);
          tekst.setText("Błędny URL: " + url + "\n" + e.getMessage());
        }
      }
    }; 
   
    adres.addActionListener(wczytajStronę);
    przycisk.addActionListener(wczytajStronę);
    
    JScrollPane suwaki = new JScrollPane(tekst);
    add(suwaki);
    Box box = new Box(BoxLayout.X_AXIS);
    box.add(przycisk);
    box.add(Box.createHorizontalStrut(10));
    box.add(adres);
    add(BorderLayout.SOUTH, box);
   
    setSize(500,400);
    setVisible(true);
  }
  
  public static void main(String[] args) {
    //aby uniknąć zakleszczeń, tworzenie GUI zawsze zlecamy dla wątku obsługi zdarzeń
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
      public void run() {
        new Zad7();
      }
    });
  }
}