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

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

Bevezető

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.

Swing

Áttekintés

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.

JavaFX

Áttekintés

Ha jól értem a Swing-gel kapcsolatos problémát, azzal, hogy erőltették a különböző operációs rendszerek közös metszetét, gyakorlatilag megragadt az 1990-es évek szintjén. A JavaFX eredménye (tehát aga a futtatható jar) már operációs rendszer függő, viszont sokkal jobban ki tudja használni az operációs rendszer adta lehetőségeket. A 8-as Java-tól kezdve a JavaFX számított az utódjának, viszont a 11-es Java-ból kivették, és azóta valóságos rémálom a JavaFX használata.

Ebben a szakaszban az első, igen rögös lépésekről olvashatunk. Itt is elmondható az, ami amúgy szint mindenhol: a teljesség igényére nem törekedtem, sőt, igazából csak az első lépésekre. További források a témával kapcsolatban a neten:

Nagyon hosszú volt az út, mire ezt a leírást elkészítettem; ki tudja, hány óra utánajárást jelentett számomra. Még akkor is repült az idő, amikor már sikerült kitapasztalnom, és csak meg szerettem volna ismételni akkor, amikor leírom. Szóval elég bonyolult!

Helló, JavaFX 8 világ!

A 8-as Java-ban benne van alapból a JavaFX, így a következő program egy az egyben elindul és fut:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
 
public class HelloFX extends Application {
 
    @Override
    public void start(Stage stage) {
        Label label = new Label("Hello, JavaFX!");
        Scene scene = new Scene(new StackPane(label), 200, 100);
        stage.setScene(scene);
        stage.show();
    }
 
    public static void main(String[] args) {
        launch();
    }
 
}

Ez fordíthatjuk és futtathatjuk parancssorból a szokásos módon (javac HelloFX.java ill. java HelloFX), vagy tetszőleges IDE-ból is, működik, feltéve, hogy 8-as Java-t használunk,

Helló, JavaFX 11 világ!

A 11-es Java-ból kikerült a JavaFX, és ettől kezdve valóságos kínszenvedés a JavaFX fejlesztés. Ha a fenti programot megpróbáljuk lefordítani, akkor egy csomó hibát ír ki, hogy nem találja a JavaFX komponenseket.

Parancssorból

Töltsük le a JavaFX Windows SDK komponenst a https://gluonhq.com/products/javafx/ oldalról, és csomagoljuk ki valamelyik könyvtárba. Mivel a 11-es Java-t használom, én a 11.0.2-es verziót töltöttem le, és a d:\programs\javafx-sdk-11.0.2\ könyvtárba csomagoltam ki.

Ezután sem a fordítás, sem a futtatás nem szokványos. Próbálkozhatunk így természetes módon így:

javac -cp d:\programs\javafx-sdk-11.0.2\lib\javafx.base.jar;d:\programs\javafx-sdk-11.0.2\lib\javafx.controls.jar;d:\programs\javafx-sdk-11.0.2\lib\javafx.graphics.jar HelloFX.java

Majd az indítással így:

java -cp .;d:\programs\javafx-sdk-11.0.2\lib\javafx.base.jar;d:\programs\javafx-sdk-11.0.2\lib\javafx.controls.jar;d:\programs\javafx-sdk-11.0.2\lib\javafx.graphics.jar HelloFX

ami önmagában nyakatekert, de nem működik; az alábbi hibát írja ki:

Error: JavaFX runtime components are missing, and are required to run this application

Fordítani így tudunk:

javac --module-path d:\programs\javafx-sdk-11.0.2\lib --add-modules javafx.controls HelloFX.java

Elindítani pedig így:

java --module-path d:\programs\javafx-sdk-11.0.2\lib --add-modules javafx.controls HelloFX

Maven segítségével

Mavenben sem úgy működnek a dolgok, ahogy azt szeretnénk. Az alábbiakra van szükség:

  • Szükség van a org.openjfx : javafx-controls : 11.0.2 függőségre.
  • Szükség van a org.openjfx : javafx-maven-plugin : 0.0.5 plugin-ra (igen, ilyen meglepően furcsa verziószámmal).
  • Indítás: mvn clean javafx:run

Archetype generálás:

mvn archetype:generate -DarchetypeGroupId=org.openjfx -DarchetypeArtifactId=javafx-archetype-simple -DarchetypeVersion=0.0.5 -DgroupId=org.openjfx -DartifactId=sample -Dversion=1.0.0 -Djavafx-version=11.0.2

Saját pom.xml:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>org.openjfx</groupId>
    <artifactId>hellofx</artifactId>
    <packaging>jar</packaging>
    <version>1.0</version>
 
    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>11.0.2</version>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>0.0.5</version>
                <configuration>
                    <mainClass>HelloFX</mainClass>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

A HelloFX.java ugyanaz, mint a fenti.

Az indítása még egyszer:

mvn clean javafx:run

Beállítás Eclipse-ben

A JavaFX Eclipse-ben különösen nehézkes

Alapbeállítás

Állítsunk be egy user library-t:

  • Window → Preferences → Java → Build Path → User Libraries
  • New… → a név legyen JavaFX; a system library-t nem kell bekapcsolni
  • A listában legyen kijelölve az imént létrehozott JavaFX → Add External JARs… → adjuh hozzá a d:\programs\javafx-sdk-11.0.2\lib\ tartalmát
  • Apply and Close

Majd hozzunk létre egy Java projektet:

  • File → New → Java project…
  • Project name: ajdunk neki egy nevet → Next
  • A Library fülön Add Library… → User Library → Next → itt válasszuk ki a JavaFX elemet → Finish
  • Finish
  • A module-info.java-t nem kell elkészíteni.
  • Az src könyvtárba adjuk hozzá a fenti HelloFX osztályt. (Alapból léttehoz neki egy csomagot; átmozgathatjuk az src gyökerébe.)

Most már lefordul, de ha megpróbáljuk futtatni, akkor a következő hibát kapjuk:

Error: Could not find or load main class HelloFX
Caused by: java.lang.NoClassDefFoundError: javafx/application/Application

Hajtsuk végre a következő lépéseket:

  • Run → Run Configuration…
  • Main fül → Main class: HelloFX
  • Arguments fül → VM arguments: —module-path d:\programs\javafx-sdk-11.0.2\lib —add-modules javafx.controls,javafx.fxml
  • Apply → Close
  • A szokásos módon indítható, pl. jobb kattintás a main-en → Run As → Java Application

e(fx)clipse

Ez egy JavaFX fejlesztéssel kapcsolatos Eclipse plugin. A fenti lépéseket nem ússzuk meg ezzel sem.

  • Help → Eclipse Marketplace…
  • Find: e(fx)clipse → Go
  • Az e(fx)clipse 3.6.0 (vagy újabb) verzió jobb alsó sarkában kattintsunk az Install gombra
  • Kövessük az útmutatót.
  • A végén újra kell indítani az Eclipse-et.

Eclipse + Maven

Ez esetben nem kell beállítani a user library-t. Ám ha a szokásos módon valósítjuk meg:

  • File → New → Project
  • Maven → Maven Project
  • Create a simple project (skip archetype selection)
  • Next → Group Id-t és Artifact Id-t kitöltjük → Finish
  • A pom.xml-t módosítjuk a fentiek alapján
  • Hozzuk létre a HelloFX.java-t a fentiek alapján
  • Biztos, ami biztos alapon jobb kattintás a projekt nevén → Properties → Java Compiler → Compiler compliance level: 11

akkor - a változatosság gyönyörködtet - az alábbi hibaüzenetet kapjuk:

Error: JavaFX runtime components are missing, and are required to run this application

Itt is hozzá kell adni a Run → Run Configuration… megfelelő eleméhez VM arguments-ként az alábbit:

--module-path d:\programs\javafx-sdk-11.0.2\lib --add-modules javafx.controls,javafx.fxml

Egy csúnya hekkelés

A fenti Maven "bohóckodást" el lehet kerülni az alábbi csúnya hekkeléssel. A pom.xml és a HelloFX.java maradjon meg a fenti, az Eclipse projektben ne állítsunk be semmit, viszont hozzuk létre ezt az osztályt:

public class HelloFXStarter {
 
    public static void main(String[] args) {
        HelloFX.main(args);
    }
 
}

Ezt elindítva rendesen elindul!

Futtatható JAR

A futtatható jar-t csak a fenti hekkeléssel tudtam készíteni. A HelloFX.java és a HelloFXStarter.java legyen a fenti, a pom.xml-t pedig egészítsük ki a következőképpen:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>hu.faragocsaba</groupId>
    <artifactId>hellofxexecjar</artifactId>
    <version>1.0</version>
 
    <properties>
        <maven.compiler.source>11</maven.compiler.source>
        <maven.compiler.target>11</maven.compiler.target>
    </properties>
 
    <dependencies>
        <dependency>
            <groupId>org.openjfx</groupId>
            <artifactId>javafx-controls</artifactId>
            <version>11.0.2</version>
        </dependency>
    </dependencies>
 
    <build>
        <plugins>
            <plugin>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-maven-plugin</artifactId>
                <version>0.0.5</version>
                <configuration>
                    <mainClass>HelloFX</mainClass>
                </configuration>
            </plugin>
 
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <version>2.2-beta-5</version>
                <executions>
                    <execution>
                        <phase>package</phase>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <configuration>
                            <archive>
                                <manifest>
                                    <mainClass>HelloFXStarter</mainClass>
                                </manifest>
                            </archive>
                            <descriptorRefs>
                                <descriptorRef>jar-with-dependencies</descriptorRef>
                            </descriptorRefs>
                        </configuration>
                    </execution>
                </executions>
            </plugin>        
        </plugins>        
    </build>
</project>

Érdemes kihangsúlyozni, hogy a javafx-maven-plugin és a maven-assembly-plugin mainClass része eltér. Ezt elég könnyű elrontani, és az esetben csak annyit látunk, hogy nem indul.

A fordítás - kivételesen - a szokásos:

mvn clean install

Ha mindent jól csináltunk, akkor a target könyvtárban létrejön egy futtatható jar fájl az alábbi néven: hellofxexecjar-1.0-jar-with-dependencies.jar. Ez egy több mint 9 MB-os fájl. Ha belenézünk, akkor a gyökérben több tucat DLL-t látunk; ez tehát Windows specifikus, más operációs rendszer alatt nem fut. Ott külön le kell fordítani.

Egy példa

Lássunk egy bővebb példát:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
 
public class JavaFxExample extends Application {
 
    @Override
    public void start(Stage stage) {
        stage.setTitle("HelloFX example");
 
        Label nameLabel = new Label("Name: ");
        TextField nameEntry = new TextField();
        Button button = new Button("Click Me");
        Label greetingLabel = new Label("Hello!");
 
        button.setOnAction(event -> {
            greetingLabel.setText("Hello, " + nameEntry.getText() + "!");
        });
 
        HBox hBox = new HBox(nameLabel, nameEntry);
        VBox vBox = new VBox(hBox, button, greetingLabel);
 
        Scene scene = new Scene(vBox, 200, 70);
        stage.setScene(scene);
        stage.show();
    }
 
    public static void main(String[] args) {
        launch();
    }
 
}

A logikája tehát hasonló a többi grafikus felülethez: vannak layout-ok (jelen esetben HBox és VBox), komponensek (Label, TextField, Button) és események (a nyomógomb setOnAction() függvénye). A részleteibe itt nem megyünk bele; a fenti linkeken találunk leírásokat.

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