Примерна задача: Създаване на “Dashboard” изглед с FXML и различни Контейнери за изглед
Ще създадем прост “Dashboard” изглед, който демонстрира как различни Контейнери за изглед могат да се комбинират за изграждане на сложен интерфейс. Всяка секция на дашборда ще използва различен Контейнер за изглед.
1. Създайте нов JavaFX проект в IntelliJ IDEA
2. Създайте нов пакет и класове
Създайте новия пакет bg.tu_varna.sit.ps.sample_task. В него създайте класовете DashboardApplication, Dashboard и Launcher.
-
src/main/java/bg/tu_varna/sit/ps/sample_task/DashboardApplication.java(Основен клас): Този клас ще стартира приложението и ще зареди нашия FXML файл.package bg.tu_varna.sit.ps.sample_task;` import javafx.application.Application; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.stage.Stage; import java.io.IOException; public class DashboardApplication extends Application { @Override public void start(Stage stage) throws IOException { // Зареждаме нашия FXML файл FXMLLoader fxmlLoader = new FXMLLoader(DashboardApplication.class.getResource("dashboard-view.fxml")); Parent root = fxmlLoader.load(); new Dashboard(root); Scene scene = new Scene(root, 900, 650); stage.setTitle("Dashboard Application"); // Заглавие на прозореца stage.setScene(scene); // Задаваме графичната сцена на прозореца stage.show(); // Показваме прозореца } } -
src/main/java/bg/tu_varna/sit/ps/sample_task/Dashboard.javaТози клас ще служи добавяне на интерактивност за нашия FXML файл. В момента няма да добавяме логика, но той е необходим за свързване на FXML с Java кода.package bg.tu_varna.sit.ps.sample_task; import javafx.scene.Parent; import javafx.scene.control.Label; public class Dashboard { private final Label headerLabel; private final Label navigationLabel; public Dashboard(Parent root) { headerLabel = (Label) root.lookup("#headerLabel"); navigationLabel = (Label) root.lookup("#navigationLabel"); init(); } private void init() { headerLabel.setText("Dashboard"); navigationLabel.setText("Home > Dashboard"); } } -
src/main/java/bg/tu_varna/sit/ps/sample_task/Launcher.java(Клас за стартиране): Този клас съдържа основния метод за стартиране на приложението.package bg.tu_varna.sit.ps.sample_task; import javafx.application.Application; public class Launcher { public static void main(String[] args) { Application.launch(DashboardApplication.class, args); } }
3. Създайте FXML файл за изгледа на дашборда
Създайте нова директория resources/bg/tu_varna/sit/ps/sample_task/ и в нея създайте FXML файл с името dashboard-view.fxml.
-
src/main/resources/bg/tu_varna/sit/ps/sample_task/dashboard-view.fxml(FXML файл): Това е мястото, където ще дефинираме нашия потребителски интерфейс, използвайки комбинация от Контейнери за изглед.<?xml version="1.0" encoding="UTF-8"?> <?import javafx.geometry.Insets?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <?import javafx.scene.paint.Color?> <?import javafx.scene.text.Font?> <BorderPane prefHeight="600.0" prefWidth="850.0" xmlns="http://javafx.com/javafx/21" xmlns:fx="http://javafx.com/fxml/1"> <top> <HBox alignment="CENTER" prefHeight="50.0" BorderPane.alignment="CENTER"> <Label text="Dashboard Header" fx:id="headerLabel"> <font> <Font name="System Bold" size="24.0"/> </font> </Label> </HBox> </top> <left> <VBox prefWidth="150.0" spacing="10.0" BorderPane.alignment="CENTER"> <padding> <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/> </padding> <background> <Background> <fills> <BackgroundFill> <fill> <Color red="0.878" green="0.878" blue="0.878"/> </fill> </BackgroundFill> </fills> </Background> </background> <Label text="Navigation" fx:id="navigationLabel"/> <Button maxWidth="Infinity" text="Section 1"/> <Button maxWidth="Infinity" text="Section 2"/> <ToggleButton fx:id="statusToggleButton" maxWidth="Infinity" text="Status"/> <Region VBox.vgrow="ALWAYS"/> <Button maxWidth="Infinity" text="Settings"/> </VBox> </left> <center> <StackPane BorderPane.alignment="CENTER"> <padding> <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/> </padding> <!-- Welcome VBox --> <VBox alignment="CENTER" spacing="20.0" visible="true"> <Label text="Welcome to your Dashboard!"/> <Label text="Select a section from the left."/> </VBox> </StackPane> </center> <bottom> <HBox alignment="CENTER_LEFT" prefHeight="30.0" BorderPane.alignment="CENTER"> <padding> <Insets bottom="5.0" left="5.0" right="5.0" top="5.0"/> </padding> <background> <Background> <fills> <BackgroundFill> <fill> <Color red="0.941" green="0.941" blue="0.941"/> </fill> </BackgroundFill> </fills> </Background> </background> <Label text="Status: Ready"/> <Region HBox.hgrow="ALWAYS"/> <Label text="Version 1.0"/> </HBox> </bottom> <right> <FlowPane hgap="5.0" vgap="5.0" prefWidth="150.0" orientation="VERTICAL" BorderPane.alignment="CENTER"> <padding> <Insets bottom="10.0" left="10.0" right="10.0" top="10.0"/> </padding> <background> <Background> <fills> <BackgroundFill> <fill> <Color red="0.816" green="0.816" blue="0.816"/> </fill> </BackgroundFill> </fills> </Background> </background> <Label text="Quick Links"/> <Button text="Link A"/> <Button text="Link B"/> <Button text="Link C"/> <Button text="Link D"/> <Button text="Link E"/> </FlowPane> </right> </BorderPane>
Обяснения на FXML файла:
BorderPane(корен): ИзползвамеBorderPaneкато основен Контейнер за изглед, тъй като той е идеален за общата структура на едно приложение с хедър (горе), футър (долу), странични навигации (ляво/дясно) и централно съдържание.- Регионът
topсъдържаHBoxза заглавието. - Регионът
leftсъдържаVBoxза навигационно меню. - Регионът
centerсъдържаStackPaneза основното съдържание (в момента само приветствие). - Регионът
bottomсъдържа другHBoxза статус бар. - Регионът
rightсъдържаFlowPaneза бързи връзки.
- Регионът
HBox(Хоризонтална кутия): Използван вtopиbottomза хоризонтално подреждане на елементи. Забележетеalignment="CENTER"иalignment="CENTER_LEFT".Region HBox.hgrow="ALWAYS"се използва като разделител, който заема цялото останало пространство, бутайки другите елементи към краищата.VBox(Вертикална кутия): Използван вleftза вертикално подреждане на бутоните за навигация.spacing="10.0"добавя 10px разстояние между бутоните.Region VBox.vgrow="ALWAYS"за да бутне “Settings” бутона най-отдолу.StackPane(Наслагващ контейнер): Използван вcenter. В момента има само единVBoxв него, но ако добавим още елементи, те ще се наслагват един върху друг в центъра.FlowPane(Поточен контейнер): Използван вrightрегиона за “Quick Links”. Сorientation="VERTICAL", бутоните се подреждат вертикално и “преливат” на нов ред, ако няма достатъчно място.hgapиvgapзадават разстояния между елементите.
4. Добавяне на GridPane и AnchorPane към центъра на StackPane
За да демонстрираме и другите Контейнери за изглед, ще променим съдържанието на StackPane в централния регион. Представете си, че искаме да покажем две различни секции: една с форма (GridPane) и една с информация (AnchorPane), които биха могли да се сменят. За целите на това упражнение ще ги направим видими едновременно, но ще са в StackPane.
Можете да замените текущия VBox в StackPane със следния код:
<!-- Welcome VBox -->
<VBox alignment="CENTER" spacing="20.0" visible="true">
<Label text="Welcome to your Dashboard!"/>
<Label text="Select a section from the left."/>
</VBox>
<!-- Пример за GridPane: Форма за потребителски данни -->
<GridPane alignment="CENTER" hgap="10.0" vgap="10.0" StackPane.alignment="CENTER" visible="false">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
</padding>
<background>
<Background>
<fills>
<BackgroundFill>
<fill>
<Color fx:constant="WHITE"/>
</fill>
</BackgroundFill>
</fills>
</Background>
</background>
<columnConstraints>
<ColumnConstraints minWidth="100.0" prefWidth="120.0"/>
<ColumnConstraints minWidth="200.0" prefWidth="250.0"/>
</columnConstraints>
<Label text="User Registration" GridPane.columnSpan="2">
<font>
<Font name="System Bold" size="16.0"/>
</font>
</Label>
<Label text="Name:" GridPane.rowIndex="1"/>
<TextField promptText="Enter name" GridPane.columnIndex="1" GridPane.rowIndex="1"/>
<Label text="Password:" GridPane.rowIndex="2"/>
<PasswordField promptText="Enter password" GridPane.columnIndex="1" GridPane.rowIndex="2"/>
<Label text="Profile Type:" GridPane.rowIndex="3"/>
<HBox spacing="10.0" alignment="CENTER_LEFT" GridPane.columnIndex="1" GridPane.rowIndex="3">
<RadioButton fx:id="personalRadio" text="Personal">
<toggleGroup>
<ToggleGroup fx:id="accountGroup"/>
</toggleGroup>
</RadioButton>
<RadioButton text="Business" toggleGroup="$accountGroup"/>
</HBox>
<Label text="Subscription:" GridPane.rowIndex="4"/>
<CheckBox fx:id="newsletterCheckBox" text="Subscribe to newsletter" GridPane.columnIndex="1"
GridPane.rowIndex="4"/>
<Label text="Notes:" GridPane.rowIndex="5" GridPane.valignment="TOP"/>
<TextArea prefHeight="80.0" promptText="Enter additional info..." wrapText="true"
GridPane.columnIndex="1" GridPane.rowIndex="5"/>
<Button maxWidth="Infinity" text="Submit" GridPane.columnIndex="1" GridPane.rowIndex="6"
defaultButton="true"/>
</GridPane>
<!-- Пример за AnchorPane: Детайлна информация -->
<AnchorPane StackPane.alignment="CENTER" visible="false">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
</padding>
<background>
<Background>
<fills>
<BackgroundFill>
<fill>
<Color red="0.973" green="0.973" blue="0.973"/>
</fill>
</BackgroundFill>
</fills>
</Background>
</background>
<Label layoutX="14.0" layoutY="14.0" text="Detailed Information" AnchorPane.leftAnchor="10.0"
AnchorPane.topAnchor="10.0">
<font>
<Font name="System Bold" size="18.0"/>
</font>
</Label>
<TextArea editable="false" layoutX="14.0" layoutY="40.0" prefHeight="150.0" prefWidth="300.0"
text="This is a detailed information section. It can contain various types of content, images, or longer texts."
wrapText="true" AnchorPane.bottomAnchor="50.0" AnchorPane.leftAnchor="10.0"
AnchorPane.rightAnchor="10.0" AnchorPane.topAnchor="50.0"/>
<Button layoutX="273.0" layoutY="210.0" mnemonicParsing="false" text="Close"
AnchorPane.bottomAnchor="10.0" AnchorPane.rightAnchor="10.0"/>
</AnchorPane>
Пояснения за добавените графични елементи:
GridPane(Мрежов контейнер):- Дефинирани са
columnConstraints(ограничения за колони) иrowConstraints(ограничения за редове), за да управляваме ширината на колоните и височината на редовете. - Всяка контрола е позиционирана с
GridPane.columnIndexиGridPane.rowIndex. GridPane.columnSpanпозволява на бутона “Submit” да заема две колони.
- Дефинирани са
AnchorPane(Закотвящ контейнер):- Използва
AnchorPane.topAnchor,AnchorPane.bottomAnchor,AnchorPane.leftAnchor,AnchorPane.rightAnchorза закачане на контролите към страните на контейнера. Това осигурява адаптивно позициониране спрямо размера наAnchorPane. Labelе закачен горе вляво,TextAreaе закачен от всички страни (с отстояние), аButtonе закачен долу вдясно.
- Използва
visible="false": В примера е зададеноvisible="false"наGridPaneиAnchorPane, така че само приветствието да се вижда първоначално. За да ги видите, променетеvisible="true"за съответната контрола. В реално приложение, това би било управлявано от Java код въз основа на избор от навигацията.
5. Стартиране на приложението
Стартирайте Launcher.java (десен бутон -> Run 'Launcher.main()'). Трябва да видите прозореца на приложението с всички дефинирани Контейнери за изглед. Експериментирайте с размера на прозореца, за да видите как Контейнерите за изглед реагират на промяната.