概述
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();
}