JavaFX SceneBuilder开发用户界面
概述
JavaFX是用于构建富互联网应用程序的Java库。使用JavaFX开发的应用程序可以在各种设备上运行,如台式计算机,手机,物联网
设备,平板电脑等。上一章主要是介绍如何应用JavaFX使用编程声明方式开发用户界面。这一章主要应用SceneBuilder开发用户界面。
使用JavaFX SceneBuilder开发用户界面
这是安装好的SceneBuilder2.0,这是fxml文件编辑器,可以进行控件拖拽来搭建用户界面。
通过FXML设置舞台
将上一章中的 StageCoach程序改为fxml构建:
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.control.*?> <?import javafx.scene.Group?> <?import javafx.scene.layout.HBox?> <?import javafx.scene.layout.VBox?> <?import javafx.scene.shape.Rectangle?> <?import javafx.scene.text.*?> <Group fx:id="rootGroup" onMouseDragged="#mouseDraggedHandler" onMousePressed="#mousePressedHandler" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.StageCoachController"> <children> <Rectangle fx:id="blue" arcHeight="50.0" arcWidth="50.0" fill="SKYBLUE" height="350.0" strokeType="INSIDE" width="250.0"/> <VBox fx:id="contentBox" layoutX="30.0" layoutY="20.0" spacing="10.0"> <children> <Text fx:id="textStageX" strokeType="OUTSIDE" strokeWidth="0.0" text="x:" textOrigin="TOP"/> <Text fx:id="textStageY" layoutX="10.0" layoutY="23.0" strokeType="OUTSIDE" strokeWidth="0.0" text="y:" textOrigin="TOP"/> <Text fx:id="textStageH" layoutX="10.0" layoutY="50.0" strokeType="OUTSIDE" strokeWidth="0.0" text="height:" textOrigin="TOP"/> <Text fx:id="textStageW" layoutX="10.0" layoutY="77.0" strokeType="OUTSIDE" strokeWidth="0.0" text="width:" textOrigin="TOP"/> <Text fx:id="textStageF" layoutX="10.0" layoutY="104.0" strokeType="OUTSIDE" strokeWidth="0.0" text="focused:" textOrigin="TOP"/> <CheckBox fx:id="checkBoxResizable" mnemonicParsing="false" text="resizable"/> <CheckBox fx:id="checkBoxFullScreen" mnemonicParsing="false" text="fullScreen"/> <HBox fx:id="titleBox"> <children> <Label fx:id="titleLabel" text="title"/> <TextField fx:id="titleTextField" text="Stage Coach"/> </children> </HBox> <Button fx:id="toBackButton" mnemonicParsing="false" onAction="#toBackEventHandler" text="toBack()"/> <Button fx:id="toFrontButton" mnemonicParsing="false" onAction="#toFrontEventHandler" text="toFront()"/> <Button fx:id="closeButton" mnemonicParsing="false" onAction="#closeEventHandler" text="close()"/> </children> </VBox> </children> </Group>
在SceneBuilder中的显示效果:
理解fxml文件
xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1"
这两条命名空间将会被FXMLLoader使用。
fx:controller="sample.StageCoachController"
它通知 JavaFX 运行时间,当前设计的 UI FXML 文件与其控制器Java 类协同工作。
因此,在加载FXML文件后,FXML文件中的顶层组节点可以在Java代码中作为舞台控制器类的根组字段访问和操作。在此FXML中
文件,我们分配了fx:id到我们创建的所有节点。当然如果不想程序化地操作节点,例如静态标签的情况,fx:id属性和控制器中的相应字段可以省略。
在程序中加载fxml
package sample;import javafx.application.Application;import javafx.fxml.FXMLLoader;import javafx.geometry.Rectangle2D;import javafx.scene.Group;import javafx.scene.Scene;import javafx.scene.paint.Color;import javafx.stage.Screen;import javafx.stage.Stage;import javafx.stage.StageStyle;import java.io.IOException;import java.util.List;public class StageCoachMainWithFxml extends Application { public static void main(String[] args) { Application.launch(args); } @Override public void start(Stage stage) throws IOException { final StageStyle stageStyle = configStageStyle(); FXMLLoader fxmlLoader = new FXMLLoader(StageCoachMainWithFxml.class .getResource("StageCoach.fxml")); Group rootGroup = fxmlLoader.load(); final StageCoachController controller = fxmlLoader.getController(); controller.setStage(stage); controller.setupBinding(stageStyle); Scene scene = new Scene(rootGroup, 250, 350); scene.setFill(Color.TRANSPARENT); stage.setScene(scene); stage.setOnCloseRequest(we -> System.out.println("Stage is closing")); stage.show(); Rectangle2D primScreenBounds = Screen.getPrimary().getVisualBounds(); stage.setX((primScreenBounds.getWidth() - stage.getWidth()) / 2); stage.setY((primScreenBounds.getHeight() - stage.getHeight()) / 4); } private StageStyle configStageStyle() { StageStyle stageStyle = StageStyle.DECORATED; List<String> unnamedParams = getParameters().getUnnamed(); if (unnamedParams.size() > 0) { String stageStyleParam = unnamedParams.get(0); if (stageStyleParam.equalsIgnoreCase("transparent")) { stageStyle = StageStyle.TRANSPARENT; } else if (stageStyleParam.equalsIgnoreCase("undecorated")) { stageStyle = StageStyle.UNDECORATED; } else if (stageStyleParam.equalsIgnoreCase("utility")) { stageStyle = StageStyle.UTILITY; } } return stageStyle; } }
理解控制类
package sample;import javafx.beans.property.SimpleStringProperty;import javafx.beans.property.StringProperty;import javafx.event.ActionEvent;import javafx.fxml.FXML;import javafx.scene.control.Button;import javafx.scene.control.CheckBox;import javafx.scene.control.Label;import javafx.scene.control.TextField;import javafx.scene.input.MouseEvent;import javafx.scene.layout.HBox;import javafx.scene.layout.VBox;import javafx.scene.shape.Rectangle;import javafx.scene.text.Text;import javafx.stage.Stage;import javafx.stage.StageStyle;/** * @author: Administrator * @date: 2021/03/18 12:52 * @description: */public class StageCoachController { @FXML private Rectangle blue; @FXML private VBox contentBox; @FXML private Text textStageX; @FXML private Text textStageY; @FXML private Text textStageH; @FXML private Text textStageW; @FXML private Text textStageF; @FXML private CheckBox checkBoxResizable; @FXML private CheckBox checkBoxFullScreen; @FXML private HBox titleBox; @FXML private Label titleLabel; @FXML private TextField titleTextField; @FXML private Button toBackButton; @FXML private Button toFrontButton; @FXML private Button closeButton; private Stage stage; private StringProperty title = new SimpleStringProperty(); private double dragAnchorX; private double dragAnchorY; public void setStage(Stage stage) { this.stage = stage; } public void setupBinding(StageStyle stageStyle) { checkBoxResizable.setDisable(stageStyle == StageStyle.TRANSPARENT || stageStyle == StageStyle.UNDECORATED); textStageX.textProperty().bind(new SimpleStringProperty("x: ") .concat(stage.xProperty().asString())); textStageY.textProperty().bind(new SimpleStringProperty("y: ") .concat(stage.yProperty().asString())); textStageW.textProperty().bind(new SimpleStringProperty("width: ") .concat(stage.widthProperty().asString())); textStageH.textProperty().bind(new SimpleStringProperty("height: ") .concat(stage.heightProperty().asString())); textStageF.textProperty().bind(new SimpleStringProperty("focused: ") .concat(stage.focusedProperty().asString())); stage.setResizable(true); checkBoxResizable.selectedProperty() .bindBidirectional(stage.resizableProperty()); checkBoxFullScreen.selectedProperty().addListener((ov, oldValue, newValue) -> stage.setFullScreen(checkBoxFullScreen.selectedProperty().getValue())); title.bind(titleTextField.textProperty()); stage.titleProperty().bind(title); stage.initStyle(stageStyle); } @FXML public void toBackEventHandler(ActionEvent e) { stage.toBack(); } @FXML public void toFrontEventHandler(ActionEvent e) { stage.toFront(); } @FXML public void closeEventHandler(ActionEvent e) { stage.close(); } @FXML public void mousePressedHandler(MouseEvent me) { dragAnchorX = me.getScreenX() - stage.getX(); dragAnchorY = me.getScreenY() - stage.getY(); } @FXML public void mouseDraggedHandler(MouseEvent me) { stage.setX(me.getScreenX() - dragAnchorX); stage.setY(me.getScreenY() - dragAnchorY); } }
唯一需要一些解释的是@FXML注释。它属于javafx.fxml包。这是一个标记注释,具有可应用于字段和方法的运行时保留。当应用于字段时,@FXML注释告诉 JavaFX 程序,该字段的名称使用FXML文件中的元素 fx:id 的值。当应用于一种方法时,@FXML注释告诉JavaFX程序该方法的名称可以用作事件处理器属性的值。字段和方法使用@FXML注解修饰,使得程序可以操作FXML中的组件。 可以对修饰的字段进行参数的绑定,绑定事件处理器。对修饰的方法可以将行为绑定到相应fxml中的组件。例如fxml文件中button设置了onAction="#toFrontEventHandler" 属性,可以在控制器中使用如下方法绑定到相应的button.
@FXML public void toFrontEventHandler(ActionEvent e) { stage.toFront(); }