当前位置 博文首页 > 文章内容

    JavaFX桌面应用-构建程序框架

    作者: 栏目:未分类 时间:2020-09-21 9:00:21

    本站于2023年9月4日。收到“大连君*****咨询有限公司”通知
    说我们IIS7站长博客,有一篇博文用了他们的图片。
    要求我们给他们一张图片6000元。要不然法院告我们

    为避免不必要的麻烦,IIS7站长博客,全站内容图片下架、并积极应诉
    博文内容全部不再显示,请需要相关资讯的站长朋友到必应搜索。谢谢!

    另祝:版权碰瓷诈骗团伙,早日弃暗投明。

    相关新闻:借版权之名、行诈骗之实,周某因犯诈骗罪被判处有期徒刑十一年六个月

    叹!百花齐放的时代,渐行渐远!



    看到JavaFX应用很多人都会说JavaFX应用太丑了,确实JavaFX比起Qt、MFC、Delphi这些界面确实丑了一点,但也不是没有可以美化的空间。
    跟网页一样,单纯HTML不加任何CSS的时候也不是很美观,JavaFX如稍微美化一下还是可以接受的。

    比如,没有任何css修饰前的JavaFX应用是这样的:

    经过简单的修饰之后的JavaFX应用是这样的:

    对比一下,很明显简单修饰美化过的界面要比原始的好看很多(个人觉得)。

    如果需要将界面改造成上图的样式,那么就不能使用JavaFX自带stage的样式,需要自己改造一下。
    本文涉及的JavaFX用法可以参考之前的文章。

    ~ JavaFX桌面应用开发系列文章传送门 ~

    1. JavaFX桌面应用开发-HelloWorld
    2. JavaFX布局神器-SceneBuilder
    3. JavaFX让UI更美观-CSS样式
    4. JavaFX桌面应用-为什么应用老是“未响应”
    5. JavaFX桌面应用-MVC模式开发,“真香”
    6. JavaFX桌面应用-loading界面
    7. JavaFX桌面应用-表格用法
    8. JavaFX桌面应用-视频转码工具
    9. JavaFX桌面应用-SpringBoot + JavaFX

    构建自己的JavaFX程序框架,需要解决以下问题:

    1. 取消默认的Stage样式
    2. 构造自己“最小化”,“关闭”面板
    3. 让程序可以拖动
    4. 处理“最小化”,“关闭”事件
    5. 构造自己的桌面程序

    取消Stage样式

    取消Stage的样式比较简单,这个在“JavaFX桌面应用-loading界面”那篇文件已经提过,就是设置Stage的Style为TRANSPARENT即可。

    stage.initStyle(StageStyle.TRANSPARENT);
    

    Style为TRANSPARENT之后,应用就没有了“最小化”、“最大化”、“关闭”面板了,如图:

    这个时候,可以用BorderPane来重构桌面框架,将原来放在Scene的root组件放在BorderPane的CENTER位置,然后自己构造的“最小化”、“最大化”、“关闭”面板放在BorderPane中的TOP位置即可。

    构造自己“最小化”、“最大化”、“关闭”面板

    按照上面设想的布局,构造自己“最小化”、“最大化”、“关闭”面板,这里我不需要“最大化”按钮,只需要“最小化”和关闭。
    整体的布局为:

    HBox[LOGO,标题,最小化,关闭]
    

    这里采用一个HBox里面放置四个Label来实现“最小化”、“关闭”面板,可以在“标题”和“最小化”中间插入一个Pane,采用HGrow将两边“撑开”。

    HBox hbox = new HBox();
    // LOGO
    Label logo = new Label();
    hbox.getChildren().add(logo);
    // TITLE
    Label titleLbl = new Label(title);
    hbox.getChildren().add(titleLbl);
    // PANE
    Pane pane = new Pane();
    HBox.setHgrow(pane, Priority.ALWAYS);
    hbox.getChildren().add(pane);
    // MIN
    Label min = new Label();
    hbox.getChildren().add(min);
    // CLOSE
    Label close = new Label();
    hbox.getChildren().add(close);
    

    代码只用到了两个容器(HBox、Pane)和一个控件(Label),而所有具体的内容交给CSS来处理:

    .hbox{
        -fx-background-color: #40444f;
    }
    
    .logo{
        -fx-background-radius: 2px;
        -fx-background-position: center center;
        -fx-background-repeat: no-repeat;
        -fx-background-size: 35px 35px;
        -fx-background-color: transparent;
        -fx-background-image: url("/images/logo.jpg");
        -fx-border-width: 0;
    }
    
    .title{
        -fx-text-fill: #fff;
    }
    
    .close{
        -fx-background-position: center center;
        -fx-background-repeat: no-repeat;
        -fx-background-size: 43px 34px;
        -fx-background-color: transparent;
        -fx-background-image: url("/images/close_0.png");
        -fx-cursor: hand;
        -fx-border-width: 0;
    }
    
    .close:hover{
        -fx-background-color: #f45454;
        -fx-background-image: url("/images/close_1.png");
        -fx-border-width: 0;
    }
    
    .min{
        -fx-background-position: center center;
        -fx-background-repeat: no-repeat;
        -fx-background-size: 43px 34px;
        -fx-background-color: transparent;
        -fx-background-image: url("/images/min_0.png");
        -fx-cursor: hand;
        -fx-border-width: 0;
    }
    
    .min:hover{
        -fx-background-color: derive(#ddd, 10%);
        -fx-background-image: url("/images/min_1.png");
        -fx-border-width: 0;
    }
    

    然后让HBox容器加载这个CSS,并为每个控件设置对一个的class:

    // HBox
    hbox.getStylesheets().add(this.getClass().getResource("/css/title-hbox.css").toExternalForm());
    hbox.getStyleClass().add(hboxCssClass);
    // LOGO
    logo.getStyleClass().add(logoCssClass);
    // TITLE
    titleLbl.getStyleClass().add(this.titleCssClass);
    // MIN
    min.getStyleClass().add(minCssClass);
    // CLOSE
    close.getStyleClass().add(closeCssClass);
    

    面板构建完成后,只需要将它跟原来Scene的root用BorderPane组装起来即可。

    stage.initStyle(StageStyle.TRANSPARENT);
    BorderPane borderPane = new BorderPane();
    borderPane.setTop(hbox);
    borderPane.setCenter(root);
    Scene scene = new Scene(borderPane);
    stage.setScene(scene);
    

    这样整个界面框架就构造完成了。

    让程序可以拖动

    界面已经构造完成了,但是会发现重构的界面无法拖动,需要自己来实现拖动功能。
    界面拖动功能可以通过鼠标的拖拽事件和位置计算来实现,通过鼠标拖拽时的坐标同步更新Stage的坐标来达到拖动效果。

    鼠标拖拽事件需要实现EventHandler<MouseEvent>接口:

    public class JFXStage implements EventHandler<MouseEvent> {
        private double xOffset = 0;
        private double yOffset = 0;
    
        @Override
        public void handle(MouseEvent event) {
              if (event.getEventType() == MouseEvent.MOUSE_PRESSED) {
                    xOffset = event.getSceneX();
                    yOffset = event.getSceneY();
              } else if (event.getEventType() == MouseEvent.MOUSE_DRAGGED) {
                    stage.setX(event.getScreenX() - xOffset);
                    if (event.getScreenY() - yOffset < 0) {
                          stage.setY(0);
                    } else {
                          stage.setY(event.getScreenY() - yOffset);
                    }
              }
        }
    }
    

    然后让需要拖拽的组件注册这个监听器即可,这里只需要头部自定义面板那块可以按住拖动即可,所以只需要HBox注册这个监听器即可:

    hbox.setOnMousePressed(this);
    hbox.setOnMouseDragged(this);
    

    这样,自己构建的JavaFX桌面框架就可以拖动了,效果如下:

    处理“最小化”、“最大化”、“关闭”事件

    最后需要做的就是处理,自定义按钮的那些事件,这个自己构建的JavaFX桌面应用才能实现最小化和关闭功能。

    最小化功能通过setIconified来实现,当用户点击min这个Label的实现,调用stage的setIconified,将程序最小化:

    min.setOnMouseClicked(e -> stage.setIconified(true));
    

    关闭按钮则复杂一点,要看有没有注册关闭回调,如果有就交给回调去处理,如果没有就直接关闭。

    close.setOnMouseClicked(e -> {
        EventHandler<WindowEvent> opt = stage.onCloseRequestProperty().get();
        if (opt != null) {
            opt.handle(new WindowEvent(stage, WindowEvent.WINDOW_CLOSE_REQUEST));
        } else {
            stage.close();
        }
    });    
    

    构建自己的桌面程序

    使用方面其他流程不变,只是不需要在构建Scene了,然后将Stage和root叫JFXStage去构建即可:

    @SpringBootApplication
    public class Main extends JFXApplication {
    	public static void main(String[] args) {
    		launch(Main.class, HelloworldView.class, new CustomStarterScreen(), args);
    	}
    
    	@Override
    	protected void beforeStageDisplay(Stage stage, Parent root, ConfigurableApplicationContext ctx) {
    		JFXStage.of(stage, root).setTitle(" JavaFX桌面应用", null).build();
    	}
    }
    

    结合Springboot,再构建自己的JavaFX桌面框架不仅界面美化了,而且开发方便了很多。

    本文的完成源码仅JFXStage这个类,可以在公众号上获取。

    关注公众号,下次将介绍JavaFX桌面应用如何实现在线升级。

    =========================================================
    关注 公众号 “HiIT青年” 发送 “javafx-jfxstage” 获取源码。

    HiIT青年
    关注公众号,阅读更多文章。