Kihagyás

GUI; Belső, lokális és anonim osztályok, lambdák

Az előadás videója elérhető a itt.

GUI – Grafikus felhasználói interfész

Az eredeti elképzelése a Java tervezőinek az volt, hogy egy olyan grafikus felhasználói interfészt készítsenek, ami egyforma jól néz ki minden platformon. Azonban ez nem sikerült az első, Java 1.0-ás megközelítésben, hiszen az ott bevezetett Abstract Window Toolkitet (AWT-t) olyan gyorsan fejlesztették ki, hogy alapvetően a tervezésnél arra sem tudtak figyelni, hogy az objektumorientált irányelveket kövessék benne. Ráadásul a kapott eredmény szép sem lett, ami köszönhető volt annak is, hogy eleve csak 4 font volt benne elérhető, a speciálisabb GUI elemek pedig szintén nem voltak használhatóak. A Java következő verzióinak egyik célja az volt, hogy ezt megpróbálják javítani.

A Java 1.1-ben megpróbálták a továbbfejleszteni az AWT-t, és objektum orientálttá tenni, azonban még ez a verzió sem volt az igazi. A Java 2-ben az AWT-t felváltotta a Swing, ami a Java Foundation Classes (JFC) GUI-val foglalkozó része, ami már egy szépen megtervezett függvénykönyvtár, bár még mindig valamennyire függ az AWT-től.

A Java 8 újabb grafikus függvény könyvtárat adott a programozók kezébe, amely már tényleg olyan, mint amilyennek eredetileg elképzelték. Ez a JavaFX, amit 2008 óta fejlesztenek. Kezdetben a JDK/JRE része volt, de a Java 11-től már külön fejlődik.

Részletesebben azonban az előadás keretein belül egyelőre a Swinggel fogunk foglalkozni, a JavaFX-et más tantárgyak majd alaposan be fogják mutatni.

JFC komponensek

a JFC tehát a Java Foundation Classes rövidítése, ami egy csomó olyan olyan tulajdonságot foglal magában, amely segíti a grafikus felhasználói interfészek összerakását és a Java alkalmazások interaktivitását.
Definíció szerint a JFC a következő elemeket tartalmazza:

Tulajdonság Leírás
Swing GUI komponensek Mindent tartalmaz a nyomógomboktól kezdve a táblázatokig.
Külalak pluginek (lásd és érezd elemek) A Swing alkalmazások pluginelhetőek úgy, hogy ezzel támogatjuk a look and feel elemek közötti választást. Például ugyanaz a program kinézhet "javasan", vagy "windowsosan". Ráadásul a Java platform támogatja a GTK+ look and feel elemeit, ami több száz ilyen kinézetet tesz elérhetővé a Swing programok számára.
Elérhetőség API A fogyatékos felhasználók számára olyan API-kat tesz elérhetővé, amelyek támogatják a Braille kijelzők használatát, vagy a képernyő felolvasást.
Java 2D API A fejlesztők számára könnyen beolvaszthatóvá teszi nagy minőségű grafikákat, szövegeket és képeket az alkalmazásokba, vagy appletekbe. A Java 2D kiterjedt API-kat tartalmaz nagy minőségű kimenetek generálására és nyomtató eszközökre való továbbítására.
Internacionalizálás A fejlesztők számára lehetővé teszik olyan applikációk fejlesztését, amelyeket mindenki a maga nyelve vagy kulturális konvenciói szerint használhat. Több ezer karakter segítségével a fejlesztők az olyan nyelveket is támogatni tudják az alkalmazásokban, mint a japán vagy a kínai.

Swing API

A következőkben tehát azt nézzük meg, hogyan lehet egyszerű swinges alkalmazásokat összerakni. Az esetek többségében ezeket a csomagokat fogjuk használni:

  • javax.swing.
  • javax.swing.event.
  • java.awt.
  • java.awt.event.*

Minden Swing programnak kell legyen legalább egy legfelső szintű tárolója a JFrame, JDialog vagy a JApplet objektumok közül. Ez utóbbi, azaz a JApplet mára már nem támogatott, maguk az appletek tették lehetővé, hogy a Java kódok böngészőn belül is futtathatóak legyenek.

A JFrame egy fő ablakot fog definiálni, a JDialog pedig egy olyan másodlagos ablakot, aminek létezése függ egy másik ablaktól. Mindenkettőre látunk példát.

A legfelső szintű tárolóknak van egy úgy nevezett tároló mezője, egy content pane, ami java.awt.Container típusú. Feladata, hogy összefogja a tárolt komponenseket, amelyeket egyesével hozzá kell adni ehhez (kivéve a menüket). A Swing-es komponensek őse a JComponent osztály, kivéve a legfelső szintű tárolókat.

(A pontos hierarchiát mindenki megnézheti alaposabban a téma utolsó bejegyzésében.)

Swinges „Hello World”

Lássuk az első Swing alkalmazást, ahol csak egy "Hello World" szöveget fogunk kiíratni egy GUI ablakra:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import javax.swing.*;        

public class HelloWorldSwing {
  public static void main(String[] args) {
    JFrame frame = new JFrame("HelloWorldSwing");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JLabel label = new JLabel("Hello World");
    frame.add(label);
    //frame.getContentPane().add(label);  // korabban
    frame.pack();
    frame.setVisible(true);
  }
}

A program kimenete ebben a formában azonban nem egységes, máshogy fest, ha a kabinetes linuxon, vagy egy solaris rendszeren, esetleg windowson futtatjuk:

linux

linux

linux

De nézzük sorról sorra, mi is történik! Először is létrehozunk egy JFrame-et, hiszen ahogy arról korábban szó volt, kell egy ilyen fő ablakot definiálni. A konstuktorban megadott szöveg lesz az, ami megjelenik az ablak fejlécében. A 6. sor utasításával azt mondjuk meg a programnak, hogy az ablakhoz tartozó x-re való klikk hatására ne csak az ablak záródjon be, de maga a program futása is fejeződjön be.

A programban definiálunk egy komponenst is, ez most egy egyszerű címke, aminek a szövege "Hello world". Ezt a címkét hozzá kell adnunk a frame-hez (illetve egész pontosan annak content pane eleméhez.)

Miután minden komponenst, amit szeretnénk, rátettünk a frame-ünkre, a frame.pack() metódusa egy akkora ablakot generál a frame-ünk számára, amiben elférnek a frame-re rakott elemek (ezt a metódust egyébként még az awt-s Window osztálytól örökli JFrame).

Végezetül a frame.setVisible(true); utasítás lesz az, ami megjeleníti az adott frame-et.

Ahhoz, hogy a programunk minden platformon ugyanúgy nézzen ki, kicsit ki kell egészítenünk azt:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
import javax.swing.*;        

public class HelloWorldSwing2 {
  public static void main(String[] args) {
    JFrame.setDefaultLookAndFeelDecorated(true);
    JFrame frame = new JFrame("HelloWorldSwing");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JLabel label = new JLabel("Hello World");
    frame.add(label);
    frame.pack();
    frame.setVisible(true);
  }
}

A JFrame.setDefaultLookAndFeelDecorated(true); utasítással azt állítjuk be, hogy a frame-ünk mindenhol hasonlóan nézzen ki:

linux

Eseménykezelés

A GUI használhatóságának egyik alapja, hogy az egyes komponensek különböző eseményeket tudnak kiváltani, amelyek hatására majd "történik valami", azaz valami aktiválódik, esetleg megnyílik, vagy bezárul egy ablak, stb.

Minden eseményt, illetve az esemény beköveztét figyelheti egy, vagy több hallgató (a továbbiakban maradjunk inkább a listener elnevezésnél), amely listenerek reagálhatnak arra, hogy az esemény bekövetkezett.

A listenerek olyan speciális osztályok, amelyek értelemszerűen megvalósítanak valamilyen Listener interface-t. A listener objektumokat az adott komponensnél be kell jegyezzük, ehhez minden komponensnek vannak különböző add metódusai, amelyek az esemény típusától függnek, amihez hozzá akarjuk rendelni a listenert.

Ezek többek között a következők lehetnek:

Esemény típusa Esemény leírása
Action tipikusan egy kattintás, vagy enter az adott objektumon
Window ablak bezárása
MouseMotion egér mozdul a komponens felett
Component láthatóvá válik a komponens
Focus a komponens megkapja a fókuszt
...

Nyomógomb és eseménykezelés

Nézzünk egy példát, amely a frame-ünk komponenséhez már eseménykezelést is társít! Legyen két komponensünk, egy nyomógomb és egy címke. A címke ténylegesen legyen egy számláló, ami azt fogja mutatni nekünk, hogy a nyomógombot hányszor nyomtuk meg (ez utóbbi lesz az eseményünk).

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
import javax.swing.*;          
import java.awt.*;
import java.awt.event.*;

class OnButtonClick implements ActionListener {
  private String prefix;
  private int clicks;
  private JLabel label;
  public OnButtonClick(String prefix, int clicks, JLabel label) {
    this.prefix=prefix;
    this.clicks=clicks;
    this.label=label;
  }
  public void actionPerformed(ActionEvent e) {
    label.setText(prefix + clicks++);
  }
}

public class SwingApplication {
  private static JFrame frame = new JFrame("SwingApplication");
  private JPanel panel = new JPanel(new GridLayout(0,1));
  private JButton button = new JButton("Swing button");
  private String prefix = "Counter: ";
  private int clicks = 1;
  private JLabel label = new JLabel(prefix + "0");

  public SwingApplication() {
    button.setMnemonic(KeyEvent.VK_W);
    button.addActionListener(new OnButtonClick(prefix,clicks,label));
    panel.add(button);
    panel.add(label);
    panel.setBorder(BorderFactory.createEmptyBorder(30,30,10,30));
    frame.add(panel,BorderLayout.CENTER);
  }
  public static void main(String[] args) {
    SwingApplication app = new SwingApplication();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
  }
}

Magában a SwingApplicationben hozzuk létre és inicializáljuk a komponenseinket. Ha kicsit figyelmesebben megnézzük a kódot, akkor rögtön észrevehetjük, hogy ezeket a komponenseket nem közvetlenül tesszük a frame-be, először egy JPanel típusú objektumba kerülnek, és csak ezt adjuk a frame-hez. Erre azért van szükség, mert több elem esetén azok elrendezéséről is gondoskodnunk kell. Jelen esetben a BorderLayout használatával azt tudjuk elérni, hogy a keret méretének definiálásával a komponseink határvonala ne essen a fő ablak oldalaira, hanem kicsit szellősebben helyezkedjenek el.

De térjünk vissza a példa központi elemére, a nyomógombra. Láthatjuk, hogy a konstruktorában megadhatjuk azt a feliratot, ami a nyomógombon fog szerepelni. Amikor beállítjuk a nyomógomb tulajdonságait a SwingApplication konstruktorában, akkor először egy mnemonic-ot definiálunk rá. Ezzel gyakorlatilag egy gyorsbillentyűt definiálunk a gombra (jelen esetben ez a 'w', ami alá lesz húzva a gomb feliratán). Ha ezt a betűt és az Alt gombot együtt nyomjuk, az pont olyan, mintha ráklikkelnénk a gombra.

swing application

És itt jön a lényeg, egy actionListenert definiálunk, ami figyeli a gomb lenyomásait, és akcióba lép, ha ez az esemény bekövetkezett.

Az első példában ezt az ActionListenert egy konkrét osztály létrehozásával valósítjuk meg (a listener objektum pedig ennek egy objektuma lesz). Az OnButtonClick osztályunk egy olyan osztály lesz, ami megvalósítja az ActionListener interfészt, azaz definiál egy actionPerformed metódust, ami majd callback módon meghívódik az esemény bekövetkezésekor.

Jelen esetben ez a listener képes kell legyen megváltoztatni a frame-ünk másik komponensének feliratát, így ezt a komponenst elérhetővé kell tenni számára. Ezt úgy érjük el, hogy amikor példányosítjuk a listener objektumot, akkor a labelt átadjuk a konstruktornak, így a listener objektum ahhoz hozzá tud majd férni, és az esemény bekövetkezésekor frissíteni tudja annak text mezejét (tulajdonképpen egy számláló értéket frissítünk, és ezt írjuk ki). Magát a text mezőnek az elemeit is persze át kell adnunk a listenernek, hogy az tudja, mi is volt az eredeti értéke a labelnek.

Nyomkodva tehát a gombot, a címke szövege változik:

swing application

Belső osztályok

A GUI alkalmazások implemetálásakor számos olyan dolognak a működését megérthetjük jobban, amire eddig kisebb hangsúlyt fordítottunk. Ilyenek például a belső osztályok.

Láttuk az előbbi példában, hogy a listener objektumnak el kell érnie a SwingApplication bizonyos elemeit. Ahhoz, hogy ezt el is érje, a konstruktorban átadtuk ezeket.

Ha azonban az OnButtonClick osztályt a SwingApplication osztályon belül definiáljuk, akkor lévén belső osztály, az objektuma, amit a külső osztály egy konkrét objektumán keresztül hoztunk létre, látni fogja a tartalmazó osztály adattagjait, így azt külön nekünk nem kell átadni, ezzel pedig egyszerűbbé válik a kód:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import javax.swing.*;          
import java.awt.*;
import java.awt.event.*;

public class SwingApplication2 {
  class OnButtonClick implements ActionListener {
    public void actionPerformed(ActionEvent e) {
      label.setText(prefix + clicks++);
    }
  }
  private static JFrame frame = new JFrame("SwingApplication");
  private JPanel panel = new JPanel(new GridLayout(0,1));
  private JButton button = new JButton("Swing button");
  private String prefix = "Counter: ";
  private int clicks = 1;
  private JLabel label = new JLabel(prefix + "0");

  public SwingApplication2() {
    button.setMnemonic(KeyEvent.VK_W);
    button.addActionListener(new OnButtonClick());
    panel.add(button);
    panel.add(label);
    panel.setBorder(BorderFactory.createEmptyBorder(30,30,10,30));
    frame.add(panel,BorderLayout.CENTER);
  }
  public static void main(String[] args) {
    SwingApplication2 app = new SwingApplication2();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
  }
}

A SwingApplication2-ben definiált OnButtonClick-nek tehát már nem kell megadni a módosítandó adatokat, azokat eléri.

Belső osztályt akkor érdemes létrehozni, ha az szorosan és kizárólag az adott osztályhoz tartozó kódot tartalmaz. Fontos, hogy ez nem kompozíció. A belső osztály látja és használja a külső osztály tagjait. Ha lefordítjuk a kódot, akkor látjuk, hogy a SwingApplication2 osztályon kívül még egy SwingApplication2$OnButtonClick osztályunk keletkezik, tehát a külső és belső osztályok nevei összefonódnak.

Lokális osztályok

Ha jobban belegondolunk, akkor az OnButtonClick osztályt az egész applikáción belül egyetlen egyszer példányosítjuk, mégpedig a SwingApplication konstruktorában. Azt is megtehetjük, hogy egyszerűen ezen metóduson belül definiáljuk ezt az osztályt, így csak ez a metódus fogja tudni példányosítani. Kicsit talán áttekinthetőbb is a kód, mert az OnClickButton definíciója pont ott van, ahol szeretnénk használni:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import javax.swing.*;          
import java.awt.*;
import java.awt.event.*;

public class SwingApplication3 {
  private static JFrame frame = new JFrame("SwingApplication");
  private JPanel panel = new JPanel(new GridLayout(0,1));
  private JButton button = new JButton("Swing button");
  private String prefix = "Counter: ";
  private int clicks = 1;
  private JLabel label = new JLabel(prefix + "0");

  public SwingApplication3() {
    class OnButtonClick implements ActionListener {
      public void actionPerformed(ActionEvent e) {
        label.setText(prefix + clicks++);
      }
    }
    button.setMnemonic(KeyEvent.VK_W);
    button.addActionListener(new OnButtonClick());
    panel.add(button);
    panel.add(label);
    panel.setBorder(BorderFactory.createEmptyBorder(30,30,10,30));
    frame.add(panel,BorderLayout.CENTER);
  }
  public static void main(String[] args) {
    SwingApplication3 app = new SwingApplication3();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
  }
}

Ha szorosan és kizárólag az adott blokkhoz (általában metódushoz) tartozik egy osztály, akkor azt az adott blokkon (metóduson) belül is definiálhatjuk, így egy olyan lokális osztályt kapunk, amely látja és használhatja a metódus osztályának tagjait, a metódus paramétereit és lényegében a konstans változóit, amik sohasem változnak.

Anonim osztályok

Mivel egyetlen egy helyen példányosítjuk ezt az OnButtonClick osztályt, így az is lehet, hogy akkor definiáljuk az osztályt, amikor épp használni szeretnénk. Ilyenkor külön el sem nevezzük, ezért egy anonim osztályuk lesz. Nem kell elnevezni, hisz a név önmagában csak azért kellene, hogy hivatkozni tudjuk, amire itt nincs szükség.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import javax.swing.*;          
import java.awt.*;
import java.awt.event.*;

public class SwingApplication4 {
  private static JFrame frame = new JFrame("SwingApplication");
  private JPanel panel = new JPanel(new GridLayout(0,1));
  private JButton button = new JButton("Swing button");
  private String prefix = "Counter: ";
  private int clicks = 1;
  private JLabel label = new JLabel(prefix + "0");

  public SwingApplication4() {
    button.setMnemonic(KeyEvent.VK_W);
    button.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent e) {
        label.setText(prefix + clicks++);
      }
    });
    panel.add(button);
    panel.add(label);
    panel.setBorder(BorderFactory.createEmptyBorder(30,30,10,30));
    frame.add(panel,BorderLayout.CENTER);
  }
  public static void main(String[] args) {
    SwingApplication4 app = new SwingApplication4();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
  }
}

Az anonim lokális osztályok lehetőséget adnak arra, hogy egyszerre definiáljunk és példányosítsunk is egy osztályt. Akkor érdemes használni, ha csak egyszer használnánk egy lokális osztályt.

A kódból látszódik, hogy ott, ahol példányosítanánk az adott osztályt, kitesszük a new kulcsszót (ez kell a példányosításhoz) majd annak az interfésznek a neve következik, amit meg szeretnénk valósítani, illetve meg kell adni egy paraméterlistát, amely a következőben definiált osztály konstruktora határoz meg (hány paraméter és milyen típusú). Ha ez megvan, akkor következik az osztály törzsének megadása.

Ha lefordítjuk a kódot, akkor az anonim osztály valami ilyesmi lesz: SwingApplication4$1.class, azaz a nevet egy sorszám fogja helyettesíteni, amely szám nem biztos, hogy minden esetben ugyanaz lesz adott osztályra nézve, ez fordítótól függ, illetve attól, milyen sorrendben fordítja le a kódban található anonim osztályokat.

Lambda kifejezések

Látható, hogy az első SwingApplication osztályunk egyre egyszerűbbé és áttekinthetőbbé vált ezekkel a hozzáadott ismeretekkel. Tovább egyszerűsíthetjük a kódot, ha azokat a anonim osztályokat, ahol csak egyetlen egy metódust kell ténylegesen implementálnunk, úgynevezett lambda kifejezésekkel helyettesítjük:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
import javax.swing.*;          
import java.awt.*;
import java.awt.event.*;

public class SwingApplication5 {
  private static JFrame frame = new JFrame("SwingApplication");
  private JPanel panel = new JPanel(new GridLayout(0,1));
  private JButton button = new JButton("Swing button");
  private String prefix = "Counter: ";
  private int clicks = 1;
  private JLabel label = new JLabel(prefix + "0");

  public SwingApplication5() {
    button.setMnemonic(KeyEvent.VK_W);
    button.addActionListener((ActionEvent e) -> {
      label.setText(prefix + clicks++);
    });
    panel.add(button);
    panel.add(label);
    panel.setBorder(BorderFactory.createEmptyBorder(30,30,10,30));
    frame.add(panel,BorderLayout.CENTER);
  }
  public static void main(String[] args) {
    SwingApplication5 app = new SwingApplication5();
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.pack();
    frame.setVisible(true);
  }
}

Nézzük a button.addActionListener metódusában megadott lambda kifejezést:

1
2
3
(ActionEvent e) - > {
    label.setText(prefix + clicks++);
}

Mivel az ActionListener actionPerformed metódusa egy ActionEventet vár paraméterül, így ez lesz a lambda kifejezés paramétere, ehhez rendeljük hozzá azt a cselekvéssort, amit tulajdonképpen az actionPerformed megvalósít.

Mivel ennek a paraméternek a típusára a fordító következtetni is tudna, így elég lenne ezt egyszerűbben is felírni:

1
2
3
e -> {
      label.setText(prefix + clicks++);
    }

Megjegyzés: ha az implementálandó metódusnak több paramétere lenne, akkor azokat vesszővel elválasztva, zárójelek között kell megadni. Egy paraméter esetén elmaradhat a zárójel. Ha csak egy utasításunk van, akkor az utasítást határoló blokk is elmaradhat.

Szövegmező

Hogy egy kicsit begyakoroljuk az eddigieket, nézzünk meg egy olyan példát, amiben az eddigieket csupán annyival egészítjük ki, hogy felveszünk egy szövegmezőt is. A konkrét feladat, hogy a szövegmezőben Celsius fokban megadott számot alakítsuk át Fahrenheitbe, és írjuk ki ezt az értéket.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class CelsiusConverter {
  JFrame frame = new JFrame("Celsius -> Fahrenheit");
  JPanel panel = new JPanel(new GridLayout(2,2));
  JTextField celsiusText = new JTextField();
  JButton convertButton = new JButton("Convert");
  JLabel celsiusLabel = new JLabel("Celsius");
  JLabel fahrenheitLabel = new JLabel("Fahrenheit");

  public CelsiusConverter() {
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    convertButton.addActionListener(e -> {
      int tempFahr = (int)((Double.parseDouble(celsiusText.getText()))*1.8+32);
      fahrenheitLabel.setText(tempFahr + " Fahrenheit");
    });
    panel.add(celsiusText);
    panel.add(celsiusLabel);
    panel.add(convertButton);
    panel.add(fahrenheitLabel);
    celsiusLabel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    fahrenheitLabel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));
    frame.add(panel, BorderLayout.CENTER);
    frame.pack();
    frame.setVisible(true);
  }
  public static void main(String[] args) {
    new CelsiusConverter();
  }
}

celsius converter

Rádiógombok

A következő példában a rádiógombok kapják a főszerepet. Adott egy rádió gombokat tartalmazó lista (lényeg, hogy egyik elem jelölhető ki), illetve adott egy nyomógomb.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

public class RadioAndDialogDemo {
  static JDialog dialog = new JDialog();
  static JPanel panel = new JPanel(new BorderLayout());
  ButtonGroup group = new ButtonGroup();
  final String defaultCommand = "def";
  final String yesNoCommand = "yn";
  final String yesNoCancelCommand = "ync";

  public static void main(String[] args) {
    dialog.setTitle("Radio Dialog");
    dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
    new RadioAndDialogDemo();
    dialog.add(panel);
    dialog.pack();
    dialog.setVisible(true);
  }

  public RadioAndDialogDemo() {
    panel.add(createRadioButtonsPanel(), BorderLayout.NORTH);
    JButton button = new JButton("Valassz");
    panel.add(button, BorderLayout.CENTER);
    JLabel label = new JLabel("Valassz!", JLabel.CENTER);
    button.addActionListener(e -> {
      String command = group.getSelection().getActionCommand();
      if (command == defaultCommand) {
        JOptionPane.showMessageDialog(dialog, "Elso");
        label.setText("OK");
      } else if (command == yesNoCommand) {
        int n = JOptionPane.showConfirmDialog(dialog, "Masodik",
                     "Ujabb kerdes", JOptionPane.YES_NO_OPTION);
        if (n == JOptionPane.YES_OPTION) label.setText("Yes");
        else if (n == JOptionPane.NO_OPTION) label.setText("No");
      } else if (command == yesNoCancelCommand) {
        int n = JOptionPane.showConfirmDialog(dialog, "Harmadik",
                     "Ujabb kerdes", JOptionPane.YES_NO_CANCEL_OPTION);
        if (n == JOptionPane.YES_OPTION) label.setText("Yes");
        else if (n == JOptionPane.NO_OPTION) label.setText("No");
        else label.setText("Cancel");
      }
    });
    label.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
    panel.add(label, BorderLayout.SOUTH);
    panel.setBorder(BorderFactory.createEmptyBorder(20,20,5,20));
  }

  private JPanel createRadioButtonsPanel() {
    JRadioButton[] radioButtons = new JRadioButton[3];
    radioButtons[0] = new JRadioButton("ez az elso");
    radioButtons[0].setActionCommand(defaultCommand);
    radioButtons[1] = new JRadioButton("ez a masodik");
    radioButtons[1].setActionCommand(yesNoCommand);
    radioButtons[2] = new JRadioButton("ez pedig a harmadik");
    radioButtons[2].setActionCommand(yesNoCancelCommand);
    for (int i = 0; i < radioButtons.length; i++)
      group.add(radioButtons[i]);
    radioButtons[0].setSelected(true);
    JPanel panel = new JPanel();
    panel.setLayout(new BoxLayout(panel,BoxLayout.PAGE_AXIS));
    panel.add(new JLabel("A lista"));
    for (int i = 0; i < radioButtons.length; i++)
      panel.add(radioButtons[i]);
    return panel;
  }
}

radio1

Amikor a gombot megnyomjuk, akkor felugrik egy dialógus ablak, amin kiíródik, mely rádió gomb volt kiválasztva, illetve attól függően, hogy hányadik eset volt a kiválasztott, nyomógombok is kerülnek a dialógus ablakra. A kiválasztott nyomógomb szövegével frissül az eredeti frame nyomógomb alatti szövege.

radio2

További komponensek

Ha valaki jobban meg szeretne ismerkedni a swinges elemekkel, akkor az alábbi osztálydiagram segíthet:

További komponensek

http://docs.oracle.com/javase/tutorial/uiswing/components/


Utolsó frissítés: 2021-05-04 07:53:32