Grafikus felhasználói felület Javában

Kategória: Java standard könyvtárak.

Áttekintés

A Java nyelv egy óriási előnye a standard grafikus felület beépítése volt. Pl. C++-ban erre nincs lehetőség, ott csak operációs rendszer specifikus grafikus felületet tudunk létrehozni. C++-ban megtanulhatjuk pl. a Windows-os MVC-t, de Linux alatt az X felületet másképp kell programoznunk. Java-ban alatt viszont tudunk olyan programot írni, aminek van grafikus felülete, és működik minden olyan operációs rendszer alatt, ahol van grafikus felület.

Történelmi áttekintés:

  • Az első Java verzióban megjelent az AWT (Abstract Windows Toolkit), ahol a kinézet platform függő volt. Ezzel lehet olyan programot írni, ami tartalmaz mondjuk nyomógombot, de az a nyomógomb másként néz ki Windows alatt, és másképp Linux grafikus felülete.
  • Még a kezdeti időszakban, egészen pontosan az 1.2-es verziótól kezdve része lett a Java-nak a Swing, ami az AWT-re épülő, de már platformfüggetlen kinézetű grafikus felület. Erről lesz szó részletesen ebben a leírásban.
  • A Swing utódaként alkották meg a JavaFX-et.

A grafikus felületekről a következő mondható el:

  • Komponensekből épül fel. Nagyon sok szabványos, jól megszokott komponens van, mint pl. nyomógomb, menü vagy beviteli mező, de természetesen minden rendszernek lehetnek sajátos, nem mindenütt jelen levő komponens típusa. A Java Swing-ben a komponens nevek J-vel kezdődnek, pl. JButton, JMenu vagy JTextArea. Mindegyik komponensnek számos eljárása van. Például - ahogy azt elvárhatjuk egy beviteli mezőtől - a JTextArea komponensnek van egy getText() eljárása, amellyel a pillanatnyilag beírt szöveget tudjuk lekérdezni. A komponensekről külön alfejezetben lesz szó.
  • A Swing-ben az alap komponens a JFrame; ezt kell példányosítani, és erre tudunk egyéb komponenseket helyezni.
  • A komponensekhez akciók rendelhetőek. Tehát megadhatjuk azt, hogy melyik eljárás fusson le, amikor a felhasználó egy olyan műveletet hajt végre, melyben az adott komponens érintett. A fenti példákban ilyen művelet lehet pl. a nyomgombra kattintás, menü kiválasztása vagy beírás egy beviteli mezőbe. Ehhez létre kell hoznunk egy ActionListener-ből származott osztályt, annak meg kell valósítanunk az void actionPerformed(ActionEvent event) eljárását, majd az adott komponens addActionListener(actionEvent) eljárását meg kell hívnunk. Egy akciót több komponenshez is rendelhetünk, és egy komponens több akciót is tartalmazhat. Az akciók egyébként az AWT-ben lettek megvalósítva, és a Swing is azt használja, tehát a komponensektől eltérően itt nincs külön Swing akció megvalósítás.
  • A komponensek fizikai elrendezéséhez elrendezés vezérlőket (layout manager) használhatunk. A JFrame osztály setLayout() eljárásával tudjuk beállítani. Néhány gyakori elrendezés vezérlő:
    • java.awt.BorderLayout: ez az alapértelmezett. A felületet 5 észre osztja: a térképekhez hasonlóan felül van észak (NORTH), alul dél (SOUTH), balra nyugat (WEST), jobbra kelet (EAST), a középen levő, általában legnagyobb terület neve pedig CENTER. Ha tehát ezt az elrendezés vezérlőt használjuk, akkor a komponens elhelyezésekor meg kell adnunk, hogy a fentiek közül hova szeretnénk helyezni az adott komponenst.
    • java.awt.GridLayout: táblázatszerű elrendezést tudunk segítségével létrehozni. Például ha létrehozunk egy 3x3-as GridLayout-ot, és hozzáadunk 9 komponenst, akkor az ennek megfelelő elrendezésben fog megjelenni.
    • java.awt.FlowLayout: folyamatosan pakolja az elemeket egymás után. Ez az alapértelmezett a panelek (JPanel) esetén (általában a JFrame-re nem szoktunk közvetlenül elemeket helyezni, hanem panelekre pakoljuk, és a paneleket helyezzük a keretre.).

Komponensek

A fontosabb komponensek az alábbiak:

  • Legfelső szintű konténerek
    • JFrame: ez az alapja a Swing alkalmazásoknak.
    • JDialog: dialógus ablakot lehet segítségével létrehozni.
    • JApplet: böngészőben futó kisalkalmazást lehet segítségével készíteni.
  • Általános célú konténerek
    • JPanel: általános célú panel, melyet a keretre lehet helyezni.
    • JScrollPane: görgethető panel
    • JSplitPane: egy vízszintes vagy függőleges vonallal elválasztott panel, melyre JPanel elemeket tudunk tenni, pl. JSplitPane sp = new JSplitPane(SwingConstants.VERTICAL, p1, p); (ahol p1 és p2 típusa JPanel). Az elválasztó általában mozgatható.
    • JTabbedPane: segítségével egymást eltakaró ablakrendszert, tabokat lehet létrehozni, pl. JTabbedPane tp=new JTabbedPane();, majd tp.add("Tab1", p1) (p1 típusa JPanel) stb.
    • JToolBar: eszköztárat lehet segítségével létrehozni, ami általában vékony és széles. Az add() eljárással tetszőeges komponens ráhelyezhető.
  • Alapvető beviteli eszközök
    • JButton: nyomógomb. Általában hozzá szokás társítani egy akció figyelőt az addActionListener() eljárással.
    • JCheckBox: bejelölhető négyzet.
    • JComboBox: legördülő kiválasztó elem. A konstruktorának kell átadni szöveg tömbként (String[]) a lehetséges értékeket. Pl. final JComboBox cb = new JComboBox(new String[]{"apple","banana","peach"});
    • JList: listát lehet vele létrehozni. Hasonlít a comboboxhoz annyiban, hogy itt is hasonlóan lehet megadni az elemeket, azok viszont mind látszódnak; a comboboxot helytakarékos listaként is felfoghatjuk, mivel az csak egy sort foglal. A listából egyszerre több elem is kiválasztható.
    • JMenu: segítségével menüt lehet létrehozni. Egészen pontosan a JMenuBar az az elem, melyet hozzá lehet adni a JFrame-hez a setJMenuBar() eljárás segítségével. A JMenuBar-hoz hozzáadhatunk az add() eljárás segítségével JMenu elemeket; ezek az alapból is látható fő menüpontok, azokhoz pedig JMenuItem elemeket, amelyek maguk a kiválasztható elemek. Az egyes menü elemekhez tipikusan hozzá szokás adni akció figyelőket az addActipnListener() eljárással.
    • JRadioButton: rádió gombot lehet segítségével létrehozni. A rádiógombok közül mindig pontosan egyet lehet kiválasztani, ezek egymást kizáró elemek. Ennélfogva csoportosítani kell őket, mert egy lapon lehet több rádiógomb halmaz is; ezt a ButtonGroup segítségével tudjuk létrehozni. Ez utóbbi képezi a rádiógombok közötti logikai kapcsolatot; a fizikait ettől függetlenül, közvetlenül kell megoldani. (A ButtonGroup tehát úgy működik, hogy létrehozunk egy példányt, hozzáadjuk a rádiógombokat, és utána azt nem használjuk.)
    • JSlider: segítségével csúszkát tudunk létrehozni. Meg kell adnunk az elrendezést, a minimális és maximális értéket, valamint a kezdeti értéket. Pl. JSlider mySlider = new JSlider(JSlider.HORIZONTAL, 1, 100, 20);
    • JSpinner: segítségével számot lehet kiválasztani. Van rajta egy kis felfelé és lefelé nyilacska, amellyel változtatni tudjuk az értéket. A paraméterül átadott SpinnerModel adja meg a működést. Pl. Spinner spinner = new JSpinner(new SpinnerNumberModel(5, 1, 10, 1); egy olyan spinnert hoz létre, melynek segítségével 1 és 10 közötti egész számot tudunk kiválasztani.
    • JTextField: egysoros beviteli mező.
    • JPasswordField: olyan beviteli mező, melyen a szöveg nem látszódik. Tipikusan jelszavak beolvasására szokás használni.
  • Összetett beviteli eszközök
    • JColorChooser: szín kiválasztó. Általában a következő formában használjuk Color color = JColorChooser.showDialog(mainFrame, "Choose color", Color.RED);
    • JTextArea: többsoros beviteli mező.
    • JEditorPane: egyszerű szövegszerkesztő. Megadható a szöveg típusa, pl. setContentType("text/plain") egyszerű szöveget jelent. A JFrame-re a setContentPane() eljárással lehet ráhelyezni.
    • JTextPane: a fenti kiterjesztése formázási lehetőségekkel.
    • JFileChooser: segítségével fájlt tudunk kiválasztani. Megadható az alapértelmezett könyvtár a setCurrentDirectory() eljárással. A dialógus ablakot a showOpenDialog() eljárással tudjuk megnyitni, melynek visszatérési értéke egy kód. Ha az JFileChooser.APPROVE_OPTION, akkor a getSelectedFile() eljárással kapjuk meg a kiválasztott fájlt.
    • JTable: segítéségével táblázatot tudunk létrehozni. A konstruktornak két paramétert kell átadni: az adatokat (String[][]) és az oszlopneveket (String[]).
    • JTree: fa szerkezetet tudunk vele létrehozni. DefaultMutableTreeNode-okat kell hozzá egymásba ágyaznunk, és a gyökér példányt átadni a JTree konstruktorának.
    • JOptionPane: egy ablakot dob fel, ahol lehetőség van kérdésre választ adni.
  • Nem szerkeszthető információ megjelenítése
    • JLabel: segítségével feliratot tudunk megjeleníteni.
    • JProgressBar: folyamat előrehaladását tudjuk vele megjeleníteni, mint pl. a fájlok letöltésekor. A konstruktornak a kezdeti és a végértéket kell megadnunk, program közben pedig a setValue() segítségével tudjuk beállítani az aktuális értéket, amit a határokat figyelembe véve arányosan megjelenít (Pl. ha a határok 0 és 100, és 75-öt adunk értékül, akkor a háromnegyedénél lesz az érték).
    • JSeparator: segítségével el tudjuk választani a komponenseket; kis vonalat rajzol közéjük. Pl. ha sok menü elem van, akkor ennek segítségével csoportosíthatjuk azokat.
    • JToolTip: rövid szöveg, ami akkor jelenik meg, ha a felhasználó egy komponens fölé húzza az egeret.

Egy példa

Az alábbi példa egy nagyon egyszerű szövegszerkesztőn keresztül bemutat néhány fontosabb komponenst.

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.nio.file.*;
import java.util.List;
 
import javax.swing.*;
 
public class SwingExample {
    private JTextArea textArea;
    private JTextField fileNameTextField;
 
    private void readFile() {
        try {
            Path path = Paths.get(fileNameTextField.getText());
            if (!Files.exists(path)) {
                Files.write(path, "This is a text".getBytes());
            }
            textArea.setText("");
            List<String> lines = Files.readAllLines(path);
            lines.forEach(line -> textArea.append(line + "\n"));
        } catch (IOException exception) {
            exception.printStackTrace();
        }
    }
 
    class OpenAction implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent event) {
            readFile();
        }
    }
 
    class SaveAction implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent event) {
            try {
                Files.write(Paths.get(fileNameTextField.getText()), textArea.getText().getBytes());
            } catch (IOException exception) {
                exception.printStackTrace();
            }
        }
    }
 
    class EditAction implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            switch (e.getActionCommand()) {
            case "Select all":
                textArea.selectAll();
                break;
            case "Cut":
                textArea.cut();
                break;
            case "Copy":
                textArea.copy();
                break;
            case "Paste":
                textArea.paste();
                break;
            }
        }
    }
 
    private JMenuBar createMenuBar() {
        JMenuBar menuBar = new JMenuBar();
 
        JMenu file = new JMenu("File");
 
        JMenuItem open = new JMenuItem("Open");
        open.addActionListener(new OpenAction());
        file.add(open);
 
        JMenuItem save = new JMenuItem("Save");
        save.addActionListener(new SaveAction());
        file.add(save);
 
        ActionListener editAction = new EditAction();
        JMenu edit = new JMenu("Edit");
 
        JMenuItem selectAll = new JMenuItem("Select all");
        selectAll.addActionListener(editAction);
        edit.add(selectAll);
 
        JMenuItem cut = new JMenuItem("Cut");
        cut.addActionListener(editAction);
        edit.add(cut);
 
        JMenuItem copy = new JMenuItem("Copy");
        copy.addActionListener(editAction);
        edit.add(copy);
 
        JMenuItem paste = new JMenuItem("Paste");
        paste.addActionListener(editAction);
        edit.add(paste);
 
        menuBar.add(file);
        menuBar.add(edit);
        return menuBar;
    }
 
    private void startProgram() {
        JFrame frame = new JFrame("Swing example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLayout(new BorderLayout());
 
        JPanel buttonPanel = new JPanel();
        JButton exitButton = new JButton("Exit");
        exitButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                System.exit(0);
            }
        });
        buttonPanel.add(exitButton);
 
        JButton lengthButton = new JButton("Length");
        lengthButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                JOptionPane.showMessageDialog(frame, "Text length: " + textArea.getText().length());
            }
        });
        buttonPanel.add(lengthButton);
        frame.getContentPane().add(buttonPanel, BorderLayout.PAGE_START);
 
        JPanel textPanel = new JPanel();
        JPanel fileNamePanel = new JPanel();
        JLabel fileNameLabel = new JLabel("File name:");
        fileNamePanel.add(fileNameLabel);
        fileNameTextField = new JTextField("myfile.txt", 15);
        fileNamePanel.add(fileNameTextField);
        textPanel.add(fileNamePanel);
        textArea = new JTextArea(3, 20);
        textPanel.add(textArea);
        readFile();
        frame.getContentPane().add(textPanel, BorderLayout.CENTER);
 
        frame.setJMenuBar(createMenuBar());
        frame.setSize(300, 200);
        frame.setVisible(true);
    }
 
    public static void main(String args[]) {
        (new SwingExample()).startProgram();
    }
}

Eredmény:

swing.png

Ez a leírás épp hogy csak ízelítőt tudott nyújtani a Java grafikus felületről. A neten számos kiváló forrás található azok számára, akik komolyabb grafikus felületet szeretnének készíteni, melyek közül én ezt tartom a legjobbnak: https://www.javatpoint.com/java-swing.

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License