当前位置:首页 > 编程语言 > JavaFX > 正文内容

如何应用JavaFX开发用户界面

lcpsky2年前 (2022-10-23)JavaFX287

概述

JavaFX是用于构建富互联网应用程序的Java库。使用JavaFX开发的应用程序可以在各种设备上运行,如台式计算机,手机,物联网
设备,平板电脑等。这一章主要是介绍如何应用JavaFX使用编程声明方式开发用户界面。

编程与声明创建用户界面

以节点为中心的UI的简介

package sample;import java.util.List;import javafx.application.Application;import javafx.beans.property.SimpleStringProperty;import javafx.beans.property.StringProperty;import javafx.geometry.Rectangle2D;import javafx.geometry.VPos;import javafx.scene.Group;import javafx.scene.Scene;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.paint.Color;import javafx.scene.shape.Rectangle;import javafx.scene.text.Text;import javafx.stage.Screen;import javafx.stage.Stage;import javafx.stage.StageStyle;import javafx.stage.WindowEvent;public class StageCoachMain extends Application {
    StringProperty title = new SimpleStringProperty();
    Text textStageX;
    Text textStageY;
    Text textStageW;
    Text textStageH;
    Text textStageF;
    CheckBox checkBoxResizable;
    CheckBox checkBoxFullScreen;    double dragAnchorX;    double dragAnchorY;    public static void main(String[] args) {
        Application.launch(args);
    }    @Override
    public void start(Stage stage) {    //设置舞台
        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;
            }
        }        final Stage stageRef = stage;
        Group rootGroup;
        TextField titleTextField;
        Button toBackButton = new Button("toBack()");
        toBackButton.setOnAction(e -> stageRef.toBack());
        Button toFrontButton = new Button("toFront()");
        toFrontButton.setOnAction(e -> stageRef.toFront());
        Button closeButton = new Button("close()");        //关闭舞台并检测何时关闭
        closeButton.setOnAction(e -> stageRef.close());        //绘制圆弧矩形
        Rectangle blue = new Rectangle(250, 350, Color.SKYBLUE);
        blue.setArcHeight(50);
        blue.setArcWidth(50);
        textStageX = new Text();
        textStageX.setTextOrigin(VPos.TOP);
        textStageY = new Text();
        textStageY.setTextOrigin(VPos.TOP);
        textStageH = new Text();
        textStageH.setTextOrigin(VPos.TOP);
        textStageW = new Text();
        textStageW.setTextOrigin(VPos.TOP);
        textStageF = new Text();
        textStageF.setTextOrigin(VPos.TOP);
        checkBoxResizable = new CheckBox("resizable");
      
        checkBoxResizable.setDisable(stageStyle == StageStyle.TRANSPARENT
                || stageStyle == StageStyle.UNDECORATED);
        checkBoxFullScreen = new CheckBox("fullScreen");
        titleTextField = new TextField("Stage Coach");
        Label titleLabel = new Label("title");        //使用UI布局容器
        HBox titleBox = new HBox(titleLabel, titleTextField);
        VBox contentBox = new VBox(
                textStageX, textStageY, textStageW, textStageH, textStageF,
                checkBoxResizable, checkBoxFullScreen,
                titleBox, toBackButton, toFrontButton, closeButton);
        contentBox.setLayoutX(30);
        contentBox.setLayoutY(20);
        contentBox.setSpacing(10);
        rootGroup = new Group(blue, contentBox);        //用节点填充场景
        Scene scene = new Scene(rootGroup, 270, 370);        //设置场景中背景
        scene.setFill(Color.TRANSPARENT);//when mouse button is pressed, save the initial position of screen
        rootGroup.setOnMousePressed((MouseEvent me) -> {
            dragAnchorX = me.getScreenX() - stageRef.getX();
            dragAnchorY = me.getScreenY() - stageRef.getY();
        });//when screen is dragged, translate it accordingly
        rootGroup.setOnMouseDragged((MouseEvent me) -> {
            stageRef.setX(me.getScreenX() - dragAnchorX);
            stageRef.setY(me.getScreenY() - dragAnchorY);
        });
        textStageX.textProperty().bind(new SimpleStringProperty("x: ")
                .concat(stageRef.xProperty().asString()));
        textStageY.textProperty().bind(new SimpleStringProperty("y: ")
                .concat(stageRef.yProperty().asString()));
        textStageW.textProperty().bind(new SimpleStringProperty("width: ")
                .concat(stageRef.widthProperty().asString()));
        textStageH.textProperty().bind(new SimpleStringProperty("height: ")
                .concat(stageRef.heightProperty().asString()));
        textStageF.textProperty().bind(new SimpleStringProperty("focused: ")
                .concat(stageRef.focusedProperty().asString()));        //控制舞台是否可以改变大小
        stage.setResizable(true);
        checkBoxResizable.selectedProperty()
                .bindBidirectional(stage.resizableProperty());        // 让舞台全屏
        checkBoxFullScreen.selectedProperty().addListener((ov, oldValue, newValue) -> {
            stageRef.setFullScreen(checkBoxFullScreen.selectedProperty().getValue());
        });
        title.bind(titleTextField.textProperty());
        stage.setScene(scene);
        stage.titleProperty().bind(title);
        stage.initStyle(stageStyle);        //关闭舞台并检测何时关闭
        stage.setOnCloseRequest((WindowEvent 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);
    }
}

确定舞台是否处于焦点位置

textStageF.textProperty().bind(new SimpleStringProperty("focused: ")
.concat(stageRef.focusedProperty().asString()));

控制舞台的z轴顺序

Button toBackButton = new Button("toBack()");
toBackButton.setOnAction(e -> stageRef.toBack());
Button toFrontButton = new Button("toFront()");
toFrontButton.setOnAction(e -> stageRef.toFront());

package sample;/**
 * @author: Administrator
 * @date: 2021/03/17 22:02
 * @description:
 */import javafx.application.Application;import javafx.beans.property.DoubleProperty;import javafx.beans.property.SimpleDoubleProperty;import javafx.beans.property.SimpleStringProperty;import javafx.collections.FXCollections;import javafx.collections.ObservableList;import javafx.geometry.HPos;import javafx.geometry.Insets;import javafx.geometry.Orientation;import javafx.geometry.VPos;import javafx.scene.Cursor;import javafx.scene.Scene;import javafx.scene.control.ChoiceBox;import javafx.scene.control.Hyperlink;import javafx.scene.control.Label;import javafx.scene.control.RadioButton;import javafx.scene.control.Slider;import javafx.scene.control.ToggleGroup;import javafx.scene.layout.FlowPane;import javafx.scene.layout.HBox;import javafx.scene.paint.Color;import javafx.scene.text.Font;import javafx.scene.text.FontWeight;import javafx.scene.text.Text;import javafx.stage.Stage;public class OnTheSceneMain extends Application {
    DoubleProperty fillVals = new SimpleDoubleProperty(255.0);
    Scene sceneRef;
    ObservableList cursors = FXCollections.observableArrayList(
            Cursor.DEFAULT,
            Cursor.CROSSHAIR,
            Cursor.WAIT,
            Cursor.TEXT,
            Cursor.HAND,
            Cursor.MOVE,
            Cursor.N_RESIZE,
            Cursor.NE_RESIZE,
            Cursor.E_RESIZE,
            Cursor.SE_RESIZE,
            Cursor.S_RESIZE,
            Cursor.SW_RESIZE,
            Cursor.W_RESIZE,
            Cursor.NW_RESIZE,
            Cursor.NONE
    );    public static void main(String[] args) {
        Application.launch(args);
    }    @Override
    public void start(Stage stage) {
        Slider sliderRef;
        ChoiceBox choiceBoxRef;
        Text textSceneX;
        Text textSceneY;
        Text textSceneW;
        Text textSceneH;
        Label labelStageX;
        Label labelStageY;
        Label labelStageW;
        Label labelStageH;        final ToggleGroup toggleGrp = new ToggleGroup();
        sliderRef = new Slider(0, 255, 255);
        sliderRef.setOrientation(Orientation.VERTICAL);
        choiceBoxRef = new ChoiceBox(cursors);
        HBox hbox = new HBox(sliderRef, choiceBoxRef);
        hbox.setSpacing(10);
        textSceneX = new Text();
        textSceneX.getStyleClass().add("emphasized-text");
        textSceneY = new Text();
        textSceneY.getStyleClass().add("emphasized-text");
        textSceneW = new Text();
        textSceneW.getStyleClass().add("emphasized-text");
        textSceneH = new Text();
        textSceneH.getStyleClass().add("emphasized-text");
        textSceneH.setId("sceneHeightText");
        Hyperlink hyperlink = new Hyperlink("lookup");
        hyperlink.setOnAction((javafx.event.ActionEvent e) -> {
            System.out.println("sceneRef:" + sceneRef);
            Text textRef = (Text) sceneRef.lookup("#sceneHeightText");
            System.out.println(textRef.getText());
        });
        RadioButton radio1 = new RadioButton("onTheScene.css");
        radio1.setSelected(true);
        radio1.setToggleGroup(toggleGrp);
        RadioButton radio2 = new RadioButton("changeOfScene.css");
        radio2.setToggleGroup(toggleGrp);
        labelStageX = new Label();
        labelStageX.setId("stageX");
        labelStageY = new Label();
        labelStageY.setId("stageY");
        labelStageW = new Label();
        labelStageH = new Label();
        FlowPane sceneRoot = new FlowPane(Orientation.VERTICAL, 20, 10, hbox,
                textSceneX, textSceneY, textSceneW, textSceneH, hyperlink,
                radio1, radio2,
                labelStageX, labelStageY,
                labelStageW,
                labelStageH);
        sceneRoot.setPadding(new Insets(0, 20, 40, 0));
        sceneRoot.setColumnHalignment(HPos.LEFT);
        sceneRoot.setLayoutX(20);
        sceneRoot.setLayoutY(40);
        sceneRef = new Scene(sceneRoot, 600, 250);
        sceneRef.getStylesheets().add("onTheScene.css");
        stage.setScene(sceneRef);
        choiceBoxRef.getSelectionModel().selectFirst();// Setup various property binding
        textSceneX.textProperty().bind(new SimpleStringProperty("Scene x: ")
                .concat(sceneRef.xProperty().asString()));
        textSceneY.textProperty().bind(new SimpleStringProperty("Scene y: ")
                .concat(sceneRef.yProperty().asString()));
        textSceneW.textProperty().bind(new SimpleStringProperty("Scene width: ")
                .concat(sceneRef.widthProperty().asString()));
        textSceneH.textProperty().bind(new SimpleStringProperty("Scene height: ")
                .concat(sceneRef.heightProperty().asString()));
        labelStageX.textProperty().bind(new SimpleStringProperty("Stage x: ")
                .concat(sceneRef.getWindow().xProperty().asString()));
        labelStageY.textProperty().bind(new SimpleStringProperty("Stage y: ")
                .concat(sceneRef.getWindow().yProperty().asString()));
        labelStageW.textProperty().bind(new SimpleStringProperty("Stage width: ")
                .concat(sceneRef.getWindow().widthProperty().asString()));
        labelStageH.textProperty().bind(new SimpleStringProperty("Stage height: ")
                .concat(sceneRef.getWindow().heightProperty().asString()));
        sceneRef.cursorProperty().bind(choiceBoxRef.getSelectionModel()
                .selectedItemProperty());
        fillVals.bind(sliderRef.valueProperty());// When fillVals changes, use that value as the RGB to fill the scene
        fillVals.addListener((ov, oldValue, newValue) -> {
            Double fillValue = fillVals.getValue() / 256.0;
            sceneRef.setFill(new Color(fillValue, fillValue, fillValue, 1.0));
        });// When the selected radio button changes, set the appropriate style sheet
        toggleGrp.selectedToggleProperty().addListener((ov, oldValue, newValue) -> {
            String radioButtonText = ((RadioButton) toggleGrp.getSelectedToggle())
                    .getText();
            sceneRef.getStylesheets().clear();
            sceneRef.getStylesheets().addAll(radioButtonText);
        });
        stage.setTitle("On the Scene");
        stage.show();// Define an unmanaged node that will display Text
        Text addedTextRef = new Text(0, -30, "");
        addedTextRef.setTextOrigin(VPos.TOP);
        addedTextRef.setFill(Color.BLUE);
        addedTextRef.setFont(Font.font("Sans Serif", FontWeight.BOLD, 16));
        addedTextRef.setManaged(false);// Bind the text of the added Text node to the fill property of the Scene
        addedTextRef.textProperty().bind(new SimpleStringProperty("Scene fill: ").
                concat(sceneRef.fillProperty()));// Add to the Text node to the FlowPane
        ((FlowPane) sceneRef.getRoot()).getChildren().add(addedTextRef);
    }
}

设置场景中的光标

sceneRef.cursorProperty().bind(choiceBoxRef.getSelectionModel()
.selectedItemProperty());

通过ID找到场景中的节点

textSceneH = new Text();
textSceneH.getStyleClass().add("emphasized-text");
textSceneH.setId("sceneHeightText");
Hyperlink hyperlink = new Hyperlink("lookup");
hyperlink.setOnAction((javafx.event.ActionEvent e) -> {
System.out.println("sceneRef:" + sceneRef);
Text textRef = (Text) sceneRef.lookup("#sceneHeightText");
System.out.println(textRef.getText());
});

场景引用中根据ID获取文本对象,并获取对象的内容。

从场景访问舞台

labelStageX.textProperty().bind(new SimpleStringProperty("Stage x: ")
.concat(sceneRef.getWindow().xProperty().asString()));
labelStageY.textProperty().bind(new SimpleStringProperty("Stage y: ")
.concat(sceneRef.getWindow().yProperty().asString()));

向场景内容序列中插入节点

// Define an unmanaged node that will display TextText addedTextRef = new Text(0, -30, "");
addedTextRef.setTextOrigin(VPos.TOP);
addedTextRef.setFill(Color.BLUE);
addedTextRef.setFont(Font.font("Sans Serif", FontWeight.BOLD, 16));
addedTextRef.setManaged(false);// Bind the text of the added Text node to the fill property of the SceneaddedTextRef.textProperty().bind(new SimpleStringProperty("Scene fill: ").
concat(sceneRef.fillProperty()));// Add the Text node to the FlowPane((FlowPane) sceneRef.getRoot()).getChildren().add(addedTextRef);

场景中用CSS来修饰节点

sceneRef.getStylesheets().add("onTheScene.css");
...code omitted...// When the selected radio button changes, set the appropriate stylesheettoggleGrp.selectedToggleProperty().addListener((ov, oldValue, newValue) -> {
String radioButtonText = ((RadioButton) toggleGrp.getSelectedToggle())
.getText();
sceneRef.getStylesheets().clear();
sceneRef.getStylesheets().addAll("/"+radioButtonText);
});

处理输入事件

  • 查询鼠标、键盘、触摸和手势事件和处理程序

  • 理解键盘事件

  • 理解鼠标事件

  • 理解触摸事件

  • 理解手势事件

场景中的动画节点

package sample;/**
 * @author: Administrator
 * @date: 2021/03/17 22:14
 * @description:
 */import javafx.animation.Animation;import javafx.animation.Interpolator;import javafx.animation.KeyFrame;import javafx.animation.KeyValue;import javafx.animation.Timeline;import javafx.application.Application;import javafx.beans.property.DoubleProperty;import javafx.beans.property.SimpleDoubleProperty;import javafx.scene.Group;import javafx.scene.Scene;import javafx.scene.control.Button;import javafx.scene.layout.HBox;import javafx.scene.paint.Color;import javafx.scene.shape.Line;import javafx.stage.Stage;import javafx.util.Duration;public class Metronome1Main extends Application {
    DoubleProperty startXVal = new SimpleDoubleProperty(100.0);
    Button startButton;
    Button pauseButton;
    Button resumeButton;
    Button stopButton;
    Line line;
    Timeline anim;    public static void main(String[] args) {
        Application.launch(args);
    }
    @Override    public void start(Stage stage) {
        anim = new Timeline(                new KeyFrame(new Duration(0.0), new KeyValue(startXVal, 100.)),                new KeyFrame(new Duration(1000.0), new KeyValue(startXVal, 300., Interpolator.LINEAR))
        );
        anim.setAutoReverse(true);
        anim.setCycleCount(Animation.INDEFINITE);
        line = new Line(0, 50, 200, 400);
        line.setStrokeWidth(4);
        line.setStroke(Color.BLUE);
        startButton = new Button("start");
        startButton.setOnAction(e -> anim.playFromStart());
        pauseButton = new Button("pause");
        pauseButton.setOnAction(e -> anim.pause());
        resumeButton = new Button("resume");
        resumeButton.setOnAction(e -> anim.play());
        stopButton = new Button("stop");
        stopButton.setOnAction(e -> anim.stop());
        HBox commands = new HBox(10,
                startButton,
                pauseButton,
                resumeButton,
                stopButton);
        commands.setLayoutX(60);
        commands.setLayoutY(420);
        Group group = new Group(line, commands);
        Scene scene = new Scene(group, 400, 500);

        line.startXProperty().bind(startXVal);
        startButton.disableProperty().bind(anim.statusProperty()
                .isNotEqualTo(Animation.Status.STOPPED));
        pauseButton.disableProperty().bind(anim.statusProperty()
                .isNotEqualTo(Animation.Status.RUNNING));
        resumeButton.disableProperty().bind(anim.statusProperty()
                .isNotEqualTo(Animation.Status.PAUSED));
        stopButton.disableProperty().bind(anim.statusProperty()
                .isEqualTo(Animation.Status.STOPPED));
        stage.setScene(scene);
        stage.setTitle("Metronome 1");
        stage.show();
    }
}


在这里插入图片描述
在这里插入图片描述


为动画使用时间线

DoubleProperty startXVal = new SimpleDoubleProperty(100.0);
...code omitted...
Timeline anim = new Timeline(new KeyFrame(new Duration(0.0), new KeyValue(startXVal, 100.)),new KeyFrame(new Duration(1000.0), new KeyValue(startXVal, 300., Interpolator.LINEAR))
);
anim.setAutoReverse(true);
anim.setCycleCount(Animation.INDEFINITE);
...code omitted...
line = new Line(0, 50, 200, 400);
line.setStrokeWidth(4);
line.setStroke(Color.BLUE);
...code omitted...
line.startXProperty().bind(startXVal);


line = LineBuilder.create()
.startY(50)
.endX(200)
.endY(400)
.strokeWidth(4)
.stroke(Color.BLUE)
.build();

为时间线插入KeyFrame

Timeline实例包含两个KeyValue实例,在1s时间内,startXVal从100线性变化到300。将这个属性绑定到line对象的startProperty属性上即可让直线运动起来。

Timeline anim = new Timeline(new KeyFrame(new Duration(0.0), new KeyValue(startXVal, 100.)),new KeyFrame(new Duration(1000.0), new KeyValue(startXVal, 300., Interpolator.LINEAR))
);

控制时间线

通过Timeline的playFromStart(),pause(),play(),stop()控制动画开始,暂停,播放,停止。

startButton = new Button("start");
startButton.setOnAction(e -> anim.playFromStart());
pauseButton = new Button("pause");
pauseButton.setOnAction(e -> anim.pause());
resumeButton = new Button("resume");
resumeButton.setOnAction(e -> anim.play());
stopButton = new Button("stop");
stopButton.setOnAction(e -> anim.stop());


扫描二维码推送至手机访问。

版权声明:本文由软件技术记录发布,如需转载请注明出处。

本文链接:https://lcpsky.top/?id=16

分享给朋友:

“如何应用JavaFX开发用户界面” 的相关文章

JavaFX UI样式开发(jfx-tab-pane)

JavaFX UI样式开发(jfx-tab-pane)

选项卡组件(jfx-tab-pane).jfx-tab-pane .headers-region > .tab > .jfx-rippler {    -jfx-rippler-fill: #E88F17;}.jfx-tab-pane .tab-header-back...

使用JavaFX开发ToDoList

使用JavaFX开发ToDoList

使用JavaFX开发ToDoList 开发流程1.创建JavaFX项目:打开你的 Java IDE(例如IntelliJ IDEA、Eclipse等),并创建一个新的 JavaFX 项目。2.设计用户界面:在Scene Builder工具中设计一个简单的用户界...

JavaFX知识合集(2023/04/09)

JavaFX知识合集(2023/04/09)

1.为啥你打的Jar包无法双击运行?HKEY_CLASSES_ROOT\Applications\javaw.exe\shell\open\command"D:\Program Files\Java\jdk1.8.0_171\bin\javaw.exe" -jar "%...