初探JavaFx
课程作业要做 CSMA/CD 协议演示,用 JavaFX 画界面比 Swing 顺手。IDEA 自带 JavaFX 模板,配合 Scene Builder 拖控件,下面是第一次搭起来时的步骤备忘。
IDEA下开发JavaFx Application
New > project > JavaFx Application
新建后会有 Main 入口和示例 FXML,先能跑通再改布局。
添加SceneBuilder
- 下载SceneBuilder
- file | setting > JavaFx > add path
Scene Builder 里改 FXML,保存后 IDEA 里刷新即可,别手改 XML 和可视化两套不同步。
设置自定义图标
primaryStage.getIcons().add(new Image("file:res/internet.png"));
图标放 res 或 resources,路径相对运行目录;打包后若图标丢,检查 Artifacts 里是否把资源目录打进去。
打包生成exe
File | project structure > Artifacts > JavaFx >(class | title | Navite Bundle)
注意目录文件要能找到
Native Bundle 会调 jpackage/JavaFX 打包工具,JDK 版本和模块路径要对;开发机 Windows 打 exe 最省事,跨平台要分别在目标系统打。
事件绑定
fxml
onAction add
在 Scene Builder 里给 Button 填 #handleSendDataPackage,或在 XML 里写 onAction="#handleSendDataPackage"。
Java
添加函数
控制器里用 @FXML 标注同名方法,参数一般是 ActionEvent。
fx:id 对象属性修改
- 添加一个fxml成员变量
- 调用setText("");
FXML 里 fx:id="host1SendNum" 对应 Java 里 @FXML private Label host1SendNum;,加载 FXML 后自动注入,再 host1SendNum.setText(...) 更新界面。
我的代码
下面是当时仿真界面的 FXML 和主类骨架,按钮事件里还没填协议逻辑,主要验证布局和资源加载:
MainApp.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.DialogPane?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.TextArea?>
<?import javafx.scene.control.TextField?>
<?import javafx.scene.layout.FlowPane?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.text.Font?>
<FlowPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8.0.121" xmlns:fx="http://javafx.com/fxml/1" fx:controller="cn.thinkmoon.CSMA_CD.MainApp">
<children>
<Pane prefHeight="400.0" prefWidth="800.0">
<children>
<Button layoutX="154.0" layoutY="206.0" mnemonicParsing="false" onAction="#handleSendDataPackage" text="发送数据包">
<font>
<Font size="14.0" />
</font></Button>
<Button layoutX="283.0" layoutY="206.0" mnemonicParsing="false" text="重置操作">
<font>
<Font size="14.0" />
</font></Button>
<TextArea layoutX="500.0" layoutY="51.0" prefHeight="299.0" prefWidth="277.0" />
<Label fx:id="host1SendNum" layoutX="43.0" layoutY="70.0" text="主机1所需发送的数据包数:">
<font>
<Font size="17.0" />
</font>
</Label>
<Label layoutX="43.0" layoutY="130.0" text="主机2所需发送的数据包数:">
<font>
<Font size="17.0" />
</font>
</Label>
<Label layoutX="52.0" layoutY="291.0" text="主机1">
<font>
<Font size="18.0" />
</font>
</Label>
<Label layoutX="410.0" layoutY="291.0" text="主机2">
<font>
<Font size="18.0" />
</font>
</Label>
<TextField layoutX="279.0" layoutY="71.0" />
<TextField layoutX="279.0" layoutY="130.0" />
<Label layoutX="292.0" layoutY="14.0" text="模拟以太网发送过程">
<font>
<Font size="17.0" />
</font>
</Label>
<Label layoutX="48.0" layoutY="327.0" style="-fx-border-width: 1; -fx-border-color: #218ada;" styleClass="tip" text="信道空闲" textFill="#218ada">
<padding>
<Insets bottom="2.0" left="2.0" right="2.0" top="1.0" />
</padding>
</Label>
<Label layoutX="406.0" layoutY="327.0" style="-fx-border-width: 1; -fx-border-color: #218ada;" styleClass="tip" text="信道空闲" textFill="#218ada">
<padding>
<Insets bottom="2.0" left="2.0" right="2.0" top="1.0" />
</padding>
</Label>
<TextField layoutX="114.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />
<TextField layoutX="140.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />
<TextField layoutX="170.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />
<TextField layoutX="199.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />
<TextField layoutX="226.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />
<TextField layoutX="257.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />
<TextField layoutX="283.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />
<TextField layoutX="311.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />
<TextField layoutX="340.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />
<TextField layoutX="369.0" layoutY="292.0" prefHeight="23.0" prefWidth="19.0" />
</children>
</Pane>
<DialogPane />
</children>
</FlowPane>
MainApp.java
package cn.thinkmoon.CSMA_CD;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.image.Image;
import javafx.stage.Stage;
import java.io.IOException;
public class MainApp extends Application {
private Stage primaryStage;
@FXML
private Label host1SendNum;
@Override
public void start(Stage primaryStage) throws Exception{
this.primaryStage = primaryStage;
initRootLayout();
}
/**
* 初始化主界面布局
*/
public void initRootLayout() {
try {
Parent root = FXMLLoader.load(getClass().getResource("view/MainApp.fxml"));
primaryStage.setTitle("CSMA/CD协议仿真及演示");
primaryStage.setScene(new Scene(root, 800, 400));
primaryStage.setResizable(false);
primaryStage.getIcons().add(new Image("file:res/internet.png"));
primaryStage.show();
} catch (IOException e) {
e.printStackTrace();
}
}
public static void main(String[] args) {
launch(args);
}
@FXML
private void handleSendDataPackage(ActionEvent event) {
}
}
FXMLLoader.load 同包下 view/MainApp.fxml 要能找到;setResizable(false) 是作业固定窗口尺寸。后续在 handleSendDataPackage 里接仿真逻辑即可。
版权声明: 本文首发于 指尖魔法屋-初探JavaFx(https://blog.thinkmoon.cn/post/520-notes-javafx-java/) 转载或引用必须申明原指尖魔法屋来源及源地址!