侧边栏壁纸
博主头像
术业有道之编程博主等级

亦是三月纷飞雨,亦是人间惊鸿客。亦是秋霜去叶多,亦是风华正当时。

  • 累计撰写 99 篇文章
  • 累计创建 50 个标签
  • 累计收到 0 条评论

目 录CONTENT

文章目录

基于openjdk11 开发 openfx 程序

Administrator
2020-10-23 / 0 评论 / 0 点赞 / 223 阅读 / 16202 字

开局一幅图,后面全靠吹

image.png

说在前面

  • openfx的版本目前最新是15,对应openjdk14,即openfxopenjdk高一个版本
  • openjdk 1.8 之后分离了gui组件,要进行桌面程序开发需要单独引用相应的jar依赖
  • openfx程序开发有2种方式,纯java代码xml+注解

一、集成开发环境必要的准备

  • idea
  • openjdk11
  • maven (用其他玩意的自行坐标转换即可)

二、开始集成

  • maven 坐标
 <dependency>
      <groupId>org.openjfx</groupId>
      <artifactId>javafx-controls</artifactId>
      <version>12</version>
 </dependency>
<!--下面这个fxml是用来使用xml加注解来完成布局等gui功能的,不是必须的,我更倾向于纯java代码开发gui的方式,所以这里我并没有引用 -->
 <dependency>
      <groupId>org.openjfx</groupId>
      <artifactId>javafx-fxml</artifactId>
      <version>12</version>
 </dependency>

三、开局图的代码

  • 不要试图运行它,运行不起来的,里面有我自己写的bean ioc和一些其他配置类(我很有良心,这行说明写在代码前面了)
  • 创建一个类 HomeView

import com.bassis.bean.annotation.Autowired;
import com.bassis.bean.annotation.Component;
import com.bassis.bean.event.ApplicationEventPublisher;
import com.robot.common.dto.UserInfoDTO;
import com.robot.common.event.ViewEvent;
import com.robot.common.support.GameTypeEnum;
import com.robot.common.support.ViewEventOperationEnum;
import com.robot.view.fx.controllers.GameController;
import com.robot.view.fx.controllers.IntroduceController;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.input.KeyCombination;
import javafx.scene.layout.BorderPane;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.Pane;
import javafx.scene.paint.Color;
import javafx.scene.shape.Line;
import javafx.scene.text.Font;
import javafx.scene.text.Text;
import javafx.stage.Stage;
import javafx.stage.WindowEvent;
import org.apache.log4j.Logger;

import java.util.Optional;

@Component
public class HomeView extends Application {
    private static final Logger logger = Logger.getLogger(HomeView.class);
    /**
     * 层级
     */
    public static final int TIER = 0;
    @Autowired
    IntroduceController introduceController;
    @Autowired
    GameController gameController;
    UserInfoDTO userInfoDTO = new UserInfoDTO();

    @Override
    public void start(Stage primaryStage) throws Exception {
        BorderPane root = new BorderPane();
        Pane pane = pane(root, primaryStage);
        pane.getChildren().addAll(left(), leftLine(), top(), topLine(), gameGridPaneList());
        primaryStage.setOnCloseRequest(new EventHandler<>() {
            @Override
            public void handle(WindowEvent event) {
                Alert alert = new Alert(Alert.AlertType.CONFIRMATION); // 创建一个确认对话框
                alert.setTitle("退出程序");
                alert.setHeaderText("确定退出程序吗?"); // 设置对话框的头部文本
                // 设置对话框的内容文本
                alert.setContentText("点击确定将关闭此页面,并终止此程序运行");
                // 显示对话框,并等待按钮返回
                // 判断返回的按钮类型是确定还是取消,再据此分别进一步处理
                Optional<ButtonType> result = alert.showAndWait();
                if (result.isPresent() && result.get() == ButtonType.OK) {
                    primaryStage.close();
                    ApplicationEventPublisher.publishEvent(new ViewEvent(HomeView.TIER, this.getClass(), ViewEventOperationEnum.CLOSE));
                } else {
                    event.consume();
                }
            }
        });
        primaryStage.show();
    }

    /**
     * 弹起 功能介绍
     *
     * @return btnIntroduce
     */
    Button btnIntroduce() {
        Button btn = new Button("功能介绍");
        btn.getStyleClass().add("btn-success");
        btn.setOnAction((ActionEvent event) -> introduceController.show());
        return btn;
    }

    /**
     * 弹起 充值页面
     *
     * @return btnVip
     */
    Button btnVip() {
        Button btn = new Button("充值");
        btn.getStyleClass().add("btn-danger");
        btn.setOnAction((ActionEvent event) -> introduceController.show());
        return btn;
    }

    /**
     * 弹起 登录页面
     *
     * @return btnLogin
     */
    Button btnLogin() {
        Button btn = new Button("登录");
        btn.getStyleClass().add("btn-primary");
        btn.setOnAction((ActionEvent event) -> introduceController.show());
        return btn;
    }

    /**
     * 退出登录
     *
     * @return btnOutLogin
     */
    Button btnOutLogin() {
        Button btn = new Button("退出登录");
        btn.getStyleClass().add("btn-primary");
        btn.setOnAction((ActionEvent event) -> logger.info("点击了退出登录按钮"));
        return btn;
    }

    /**
     * 左侧
     *
     * @return laft
     */
    GridPane left() {
        GridPane grid = new GridPane();
//        grid.setGridLinesVisible(true);
        grid.setLayoutX(10);
        grid.setLayoutY(30);
        //设置上下行的间距
        grid.setVgap(20);
        //设置左右列的间距
        grid.setHgap(5);
        //设置表格与容器边框的外层间距
        grid.setPadding(new Insets(5, 5, 5, 5));
        ImageView robotImage = new ImageView(UserInfoDTO.ROBOT_IMAGE);
        robotImage.setFitWidth(180);
        robotImage.setFitHeight(180);
        grid.add(robotImage, 0, 0, 2, 1);
        if (userInfoDTO.getLogin()) {
            //已登录
            Label labelTel = new Label("手机号:");
            labelTel.setFont(Font.font(15));
            Text tel = new Text(userInfoDTO.getTel());
            tel.getStyleClass().add("text-success");
            grid.add(labelTel, 0, 1);
            grid.add(tel, 1, 1);

            Label labelOverdueTime = new Label("到期时间:");
            labelOverdueTime.setFont(Font.font(15));
            Text overdueTime = new Text(userInfoDTO.getOverdueTime());
            overdueTime.getStyleClass().add("text-success");
            grid.add(labelOverdueTime, 0, 2);
            grid.add(overdueTime, 1, 2);

            grid.add(btnOutLogin(), 0, 3);
            grid.add(btnVip(), 1, 3);
            grid.add(btnIntroduce(), 0, 4);
        } else {
            //未登录
            Label labelTel = new Label("当前为:");
            labelTel.setFont(Font.font(15));
            Text tel = new Text("游客");
            tel.getStyleClass().add("text-success");
            grid.add(labelTel, 0, 1);
            grid.add(tel, 1, 1);
            grid.add(btnLogin(), 0, 2);
            grid.add(btnIntroduce(), 1, 2);
        }
        return grid;
    }


    /**
     * 左侧线条
     *
     * @return leftLine
     */
    Line leftLine() {
        Line line = new Line();
        line.setStartX(210);
        line.setStartY(30);
        line.setEndX(210);
        line.setEndY(600);
        line.setStroke(Color.YELLOWGREEN);
        return line;
    }

    /**
     * 右侧顶部
     *
     * @return top
     */
    Label top() {
        Label label = new Label("游戏列表");
        label.setTextFill(Color.WHITE);
        label.setFont(Font.font(20));
        label.setLayoutX(220);
        label.setLayoutY(40);
        label.getStyleClass().add("lbl-warning");
        return label;
    }

    /**
     * 左侧线条
     *
     * @return leftLine
     */
    Line topLine() {
        Line line = new Line();
        line.setStartX(220);
        line.setStartY(70);
        line.setEndX(800);
        line.setEndY(70);
        line.setStroke(Color.YELLOWGREEN);
        return line;
    }

    /**
     * 游戏列表
     *
     * @return gameTab1
     */
    GridPane gameGridPaneList() {
        GridPane grid = new GridPane();
//        grid.setGridLinesVisible(true);
        grid.setLayoutX(220);
        grid.setLayoutY(80);
        //设置上下行的间距
        grid.setVgap(20);
        //设置左右列的间距
        grid.setHgap(20);
        //设置表格与容器边框的外层间距
        grid.setPadding(new Insets(5, 5, 5, 5));

        ImageView imageView1 = new ImageView(GameTypeEnum.GAME1.getImageUrl());
        imageView1.setFitHeight(80);
        imageView1.setFitWidth(80);
        Label labelExplain1 = new Label(GameTypeEnum.GAME1.getExplain());
        labelExplain1.setFont(Font.font(18));
        Label labelAbbreviations1 = new Label(GameTypeEnum.GAME1.getAbbreviations());
        labelAbbreviations1.setFont(Font.font(15));
        grid.add(imageView1, 0, 0, 1, 3);
        grid.add(labelExplain1, 1, 1, 1, 1);
        grid.add(labelAbbreviations1, 1, 2, 1, 1);
        imageView1.setOnMouseClicked(actionEvent -> actionEvent(GameTypeEnum.GAME1));
        labelExplain1.setOnMouseClicked(actionEvent -> actionEvent(GameTypeEnum.GAME1));
        labelAbbreviations1.setOnMouseClicked(actionEvent -> actionEvent(GameTypeEnum.GAME1));


        ImageView imageView2 = new ImageView(GameTypeEnum.GAME2.getImageUrl());
        imageView2.setFitHeight(80);
        imageView2.setFitWidth(80);
        Label labelExplain2 = new Label(GameTypeEnum.GAME2.getExplain());
        labelExplain2.setFont(Font.font(18));
        Label labelAbbreviations2 = new Label(GameTypeEnum.GAME2.getAbbreviations());
        labelAbbreviations2.setFont(Font.font(15));
        grid.add(imageView2, 4, 0, 1, 3);
        grid.add(labelExplain2, 5, 1, 1, 1);
        grid.add(labelAbbreviations2, 5, 2, 1, 1);
        imageView2.setOnMouseClicked(actionEvent -> actionEvent(GameTypeEnum.GAME2));
        labelExplain2.setOnMouseClicked(actionEvent -> actionEvent(GameTypeEnum.GAME2));
        labelAbbreviations2.setOnMouseClicked(actionEvent -> actionEvent(GameTypeEnum.GAME2));

        ImageView imageView3 = new ImageView(GameTypeEnum.GAME3.getImageUrl());
        imageView3.setFitHeight(80);
        imageView3.setFitWidth(80);
        Label labelExplain3 = new Label(GameTypeEnum.GAME3.getExplain());
        labelExplain3.setFont(Font.font(18));
        Label labelAbbreviations3 = new Label(GameTypeEnum.GAME3.getAbbreviations());
        labelAbbreviations3.setFont(Font.font(15));
        grid.add(imageView3, 0, 3, 1, 3);
        grid.add(labelExplain3, 1, 4, 1, 1);
        grid.add(labelAbbreviations3, 1, 5, 1, 1);
        imageView3.setOnMouseClicked(actionEvent -> actionEvent(GameTypeEnum.GAME3));
        labelExplain3.setOnMouseClicked(actionEvent -> actionEvent(GameTypeEnum.GAME3));
        labelAbbreviations3.setOnMouseClicked(actionEvent -> actionEvent(GameTypeEnum.GAME3));

        ImageView imageView4 = new ImageView(GameTypeEnum.GAME4.getImageUrl());
        imageView4.setFitHeight(80);
        imageView4.setFitWidth(80);
        Label labelExplain4 = new Label(GameTypeEnum.GAME4.getExplain());
        labelExplain4.setFont(Font.font(18));
        Label labelAbbreviations4 = new Label(GameTypeEnum.GAME4.getAbbreviations());
        labelAbbreviations4.setFont(Font.font(15));
        grid.add(imageView4, 4, 3, 1, 3);
        grid.add(labelExplain4, 5, 4, 1, 1);
        grid.add(labelAbbreviations4, 5, 5, 1, 1);
        imageView4.setOnMouseClicked(actionEvent -> actionEvent(GameTypeEnum.GAME4));
        labelExplain4.setOnMouseClicked(actionEvent -> actionEvent(GameTypeEnum.GAME4));
        labelAbbreviations4.setOnMouseClicked(actionEvent -> actionEvent(GameTypeEnum.GAME4));
        return grid;
    }

    /**
     * 点击右侧 grid后的事件
     *
     * @param gameTypeEnum 游戏类型
     */
    void actionEvent(GameTypeEnum gameTypeEnum) {
        gameController.show(gameTypeEnum);
    }

    /**
     * 主页面的全局pane
     *
     * @return pane
     */
    Pane pane(BorderPane root, Stage primaryStage) {
        Scene scene = new Scene(root, 800, 600);
        scene.getStylesheets().add("org/kordamp/bootstrapfx/bootstrapfx.css");
        Pane pane = new Pane();
        pane.getStyleClass().add("panel-info");
        root.getChildren().add(pane);
        primaryStage.setTitle("robot");
        primaryStage.setScene(scene);
        return pane;
    }

    /**
     * 顶部菜单
     *
     * @param root         节点
     * @param primaryStage 对象
     * @return menuBar
     */
    @Deprecated
    MenuBar menuBar(BorderPane root, Stage primaryStage) {
        //创建一个菜单工具栏
        MenuBar menuBar = new MenuBar();
        menuBar.prefWidthProperty().bind(primaryStage.widthProperty());
        root.setTop(menuBar);
        Menu fileMenu = new Menu("用户");
        menuBar.getMenus().add(fileMenu);

        MenuItem menuItem1 = new MenuItem("menu1");

        Menu menuGroup = new Menu("分组");
        ToggleGroup tGroup = new ToggleGroup();
        RadioMenuItem menuGroupItem1 = new RadioMenuItem("menuGroup1");
        menuGroupItem1.setToggleGroup(tGroup);
        menuGroupItem1.setSelected(true);
        menuGroupItem1.setUserData("menuGroup1");
        RadioMenuItem menuGroupItem2 = new RadioMenuItem("menuGroup2");
        //快捷键
        menuGroupItem2.setAccelerator(KeyCombination.valueOf("ctrl+m"));

        menuGroupItem2.setToggleGroup(tGroup);
        menuGroupItem2.setUserData("menuGroup2");
        menuGroup.getItems().addAll(menuGroupItem1, menuGroupItem2);
        //处理菜单项的选中事件
        tGroup.selectedToggleProperty().addListener((ov, old_toggle, new_toggle) -> {
            if (tGroup.getSelectedToggle() != null) {
                String menuGroupItemName = tGroup.getSelectedToggle().getUserData().toString();
                System.out.println(menuGroupItemName);
            }
        });


        MenuItem exitLoginMenuItem = new MenuItem("退出登录");
        menuItem1.setOnAction(actionEvent -> System.out.println("menu1"));
        exitLoginMenuItem.setOnAction(actionEvent -> System.out.println("退出登录"));

        fileMenu.getItems().addAll(menuItem1, menuGroup, exitLoginMenuItem);

        return menuBar;
    }
}

恭喜第一个基于openfxGUI程序就完成了,是不是很ez

  • 看到openfx官网上推荐几个工具包,我用了下,还不错,都是开源的,不想用就自己撸,轮子谁都造过。
<!-- 基于bootstrap做的推特布局 -->
 <dependency>
            <groupId>org.kordamp.bootstrapfx</groupId>
            <artifactId>bootstrapfx-core</artifactId>
            <version>0.2.4</version>
</dependency>
<!-- from表单的相关扩展,如验证器等 -->
<dependency>
            <groupId>com.dlsc.formsfx</groupId>
            <artifactId>formsfx-core</artifactId>
            <version>11.3.2</version>
</dependency>

谈谈使用感受

  • openfxswing相比,是一个大道至简的体验,繁杂的东西没那么多,灵活性很高
  • openfx的官网东西不少,但是误导性是真的强,我被带偏下载了openfx-sdk各种配置,你敢信
  • 文档说要我在ideaVM Options中设置 --module-path ${PATH_TO_FX} --add-modules javafx.controls,javafx.fxml 其中 ${PATH_TO_FX} 就是那个openfx-sdk
  • 运行它其实只需要正常的run 或者 maven打包后直接 java -jar启动,其他花里胡哨的都不接地气

个人公众号

0

评论区