Перейти к основному содержимому

Первая программа на JavaFX

Разработчику Архитектору

Первая программа на JavaFX

Где применяют JavaFX

JavaFX (OpenJFX) — рекомендуемый стек для новых desktop-приложений на Java: CSS, FXML, анимации, TableView, диалоги. С Java 11 библиотека подключается через Maven или Gradle; в JDK «из коробки» её уже нет.

Мы соберём «Конвертер °C → °F» и разберём Application.launch() — без него окно не останется на экране, как mainloop() в Tkinter или SwingUtilities.invokeLater + видимое окно в Swing.

Теория: 311.md. Элементы UI по рецептам: 3112.md. Swing без зависимостей: Практические примеры — Swing.


Что получится

Поле ввода, кнопки «Перевести» и «Выход», метка результата; Enter в поле вызывает расчёт.


Подготовка проекта (Maven)

Минимальный pom.xml для Java 17 и OpenJFX 21:

<project>
<modelVersion>4.0.0</modelVersion>
<groupId>com.example</groupId>
<artifactId>fx-demo</artifactId>
<version>1.0.0</version>

<properties>
<maven.compiler.release>17</maven.compiler.release>
<javafx.version>21.0.2</javafx.version>
</properties>

<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>${javafx.version}</version>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.8</version>
<configuration>
<mainClass>com.example.HelloFx</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>

Запуск из каталога проекта:

mvn javafx:run

Подробнее о структуре каталогов — Структуры проекта.


Минимальное окно


package com.example;

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;

public class HelloFx extends Application {

@Override
public void start(Stage stage) {
stage.setTitle("Привет, JavaFX");
stage.setScene(new Scene(new Label("Окно работает"), 320, 120));
stage.show();
}

public static void main(String[] args) {
launch(args);
}
}

Разбор:

  • Application — точка входа JavaFX; платформа вызывает start(Stage).
  • Stage — окно; Scene — содержимое с корневым узлом и размером.
  • launch(args) запускает UI-поток и цикл событий; без show() окно не видно.

Конвертер температуры


package com.example;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TextField;
import javafx.scene.input.KeyCode;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.stage.Stage;

public class ConverterApp extends Application {

private TextField celsiusField;
private Label resultLabel;

private void convert() {
String raw = celsiusField.getText().trim().replace(',', '.');
try {
double celsius = Double.parseDouble(raw);
double fahrenheit = celsius * 9 / 5 + 32;
resultLabel.setText(String.format("%.1f °C = %.1f °F", celsius, fahrenheit));
} catch (NumberFormatException ex) {
Alert alert = new Alert(Alert.AlertType.ERROR);
alert.setTitle("Ошибка");
alert.setHeaderText(null);
alert.setContentText("Введите число, например 25");
alert.showAndWait();
}
}

@Override
public void start(Stage stage) {
GridPane grid = new GridPane();
grid.setHgap(10);
grid.setVgap(10);
grid.setPadding(new Insets(16));
grid.setAlignment(Pos.CENTER);

grid.add(new Label("Температура (°C):"), 0, 0);
celsiusField = new TextField();
celsiusField.setPromptText("25");
celsiusField.setPrefColumnCount(8);
grid.add(celsiusField, 1, 0);

resultLabel = new Label("—");
grid.add(resultLabel, 0, 1, 2, 1);

Button convertBtn = new Button("Перевести");
convertBtn.setOnAction(e -> convert());
Button exitBtn = new Button("Выход");
exitBtn.setOnAction(e -> stage.close());

HBox buttons = new HBox(8, convertBtn, exitBtn);
buttons.setAlignment(Pos.CENTER);
grid.add(buttons, 0, 2, 2, 1);

celsiusField.setOnKeyPressed(e -> {
if (e.getCode() == KeyCode.ENTER) {
convert();
}
});

Scene scene = new Scene(grid, 340, 160);
stage.setTitle("Конвертер температуры");
stage.setResizable(false);
stage.setScene(scene);
stage.show();
celsiusField.requestFocus();
}

public static void main(String[] args) {
launch(args);
}
}

Разбор:

  • convert() читает текст поля, парсит число и обновляет resultLabel.
  • NumberFormatException перехватывает нечисловой ввод; Alert показывает сообщение об ошибке.
  • GridPane выравнивает метки и поля в сетке; HBox группирует кнопки в ряд.
  • setOnAction и setOnKeyPressed с KeyCode.ENTER — два способа вызвать одну логику.

GridPane и VBox

  • GridPane — таблица строк и столбцов; удобен для форм «метка | поле».
  • VBox / HBox — вертикальный или горизонтальный стек элементов.

В одном Parent у каждого дочернего узла одна позиция; для сложных форм вкладывают панели друг в друга.


Диалоги и меню (кратко)

Выбор файла:


import javafx.stage.FileChooser;

FileChooser chooser = new FileChooser();
chooser.setTitle("Выберите файл");
chooser.getExtensionFilters().add(
new FileChooser.ExtensionFilter("Текст", "*.txt")
);
java.io.File file = chooser.showOpenDialog(stage);
if (file != null) {
// чтение file
}

Меню:


import javafx.scene.control.Menu;
import javafx.scene.control.MenuBar;
import javafx.scene.control.MenuItem;

MenuBar menuBar = new MenuBar();
Menu fileMenu = new Menu("Файл");
MenuItem exitItem = new MenuItem("Выход");
exitItem.setOnAction(e -> stage.close());
fileMenu.getItems().add(exitItem);
menuBar.getMenus().add(fileMenu);

import javafx.scene.layout.BorderPane;

BorderPane root = new BorderPane();
root.setTop(menuBar);
root.setCenter(grid);
stage.setScene(new Scene(root, 340, 200));

Частые ошибки

СимптомПричина
Окно «мигает» и закрываетсяНет launch() или show()
Module javafx.controls not foundOpenJFX не в classpath / Maven
IllegalStateException: Not on FX application threadUI меняют из фонового потока
Интерфейс «зависает»Долгая работа в setOnAction — вынесите в Task
Error: JavaFX runtime components are missingЗапуск java без --module-path OpenJFX

Что попробовать

  1. Перепишите форму на VBox: метка, поле, результат, ряд кнопок.
  2. Добавьте CSS: scene.getStylesheets().add(".../app.css") и класс -fx-font-size.
  3. Сохраните результат в файл через FileChooser.showSaveDialog.
  4. Вынесите разметку в FXML — см. 311.md.

Дальше

ЦельМатериал
Справочник API3112.md
Swing в JDK без Maven131.md — Swing
Потоки и UIJVM, память и потоки
Теория десктопаАрхитектура десктопных приложений · 112.md · раздел «Десктопные приложения»

См. также

Другие статьи этого же раздела в боковом меню (как на странице "О разделе").