开局一幅图,后面全靠吹
说在前面
openfx
的版本目前最新是15
,对应openjdk
为14
,即openfx
比openjdk
高一个版本- 在
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;
}
}
恭喜第一个基于openfx
的GUI
程序就完成了,是不是很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>
谈谈使用感受
openfx
与swing
相比,是一个大道至简的体验,繁杂的东西没那么多,灵活性很高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
启动,其他花里胡哨的都不接地气
评论区