JDK 和 JavaFX SDK
需要使用JDK11, 推薦使用 https://adoptium.net/releases.html
JDK11
JavaFX 11 不再是JDK的一部分, 需要單獨安裝, 或者直接通過Maven Dependency引入.
參考 https://stackoverflow.com/questions/52467561/intellij-cant-recognize-javafx-11-with-openjdk-11
Start Guide: https://openjfx.io/openjfx-docs/#introduction
- JavaFX 11 is not part of the JDK anymore
- You can get it in different flavors, either as an SDK or as regular dependencies (maven/gradle).
- You will need to include it to the module path of your project, even if your project is not modular.
如果不使用Maven, 需要在 https://gluonhq.com/products/javafx/ 下載對應版本的sdk,
JDK9之后的模塊化
https://www.oracle.com/corporate/features/understanding-java-9-modules.html
不使用 Maven 創建 JavaFX 項目
- IDEA 直接用菜單新建JavaFX項目, 但是這種只適合 JDK8
- 如何在IDEA下創建JavaFX項目的說明 https://openjfx.io/openjfx-docs/#IDE-Intellij
例子
使用 Maven 創建JavaFX項目
使用 Maven 創建 JavaFX 項目是較簡單方便的一種方式, 不需要關心包依賴關系, 只需要手工初始化一個項目結構, 剩下的事都可以交給Maven處理.
1. 項目結構
項目結構如下, 其中resources目錄下的資源文件, 可以放在 resources 根目錄, 也可以放到resources/org/openjfx, 兩者在App.java中的載入方式不同
├── javafx_test01
│ ├── pom.xml
│ ├── src
│ │ └── main
│ │ ├── java
│ │ │ ├── com
│ │ │ │ └── rockbb
│ │ │ │ ├── App.java
│ │ │ │ ├── PrimaryController.java
│ │ │ │ └── SecondaryController.java
│ │ │ └── module-info.java
│ │ └── resources
│ │ └── com
│ │ └── rockbb
│ │ ├── primary.fxml
│ │ ├── secondary.fxml
│ │ └── styles.css
└── settings.xml
2. pom.xml
指定JDK版本為11, javafx版本為17.0.1, javafx.maven.plugin使用最新的0.0.8
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.rockbb</groupId>
<artifactId>javafx-test01</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.release>11</maven.compiler.release>
<javafx.version>17.0.1</javafx.version>
<javafx.maven.plugin.version>0.0.8</javafx.maven.plugin.version>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>${javafx.version}</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>${javafx.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<release>${maven.compiler.release}</release>
<source>${maven.compiler.release}</source>
<target>${maven.compiler.release}</target>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>${javafx.maven.plugin.version}</version>
<configuration>
<jlinkImageName>hellofx</jlinkImageName>
<launcher>launcher</launcher>
<mainClass>hellofx/org.openjfx.App</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
3. module-info.java
這里定義項目模塊的可見度, 反射的可見度, 以及依賴的其他模塊. 后面的opens ... to 和 exports 需要使用自己工程的包名
module hellofx {
requires javafx.controls;
requires javafx.fxml;
opens com.rockbb to javafx.fxml;
exports com.rockbb;
}
4. App.java
這是應用的入口. 下面的載入方式對應資源文件在根目錄, 如果要按 package 放, 去掉其中的.getClassLoader()
就可以了
package com.rockbb;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
public class App extends Application {
private static Scene scene;
@Override
public void start(Stage stage) throws IOException {
scene = new Scene(loadFXML("primary"));
scene.getStylesheets().add(getClass().getResource("styles.css").toExternalForm());
stage.setScene(scene);
stage.show();
}
static void setRoot(String fxml) throws IOException {
scene.setRoot(loadFXML(fxml));
}
private static Parent loadFXML(String fxml) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(App.class.getResource(fxml + ".fxml"));
return fxmlLoader.load();
}
public static void main(String[] args) {
launch();
}
}
5. PrimaryController.java
package com.rockbb;
import java.io.IOException;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
public class PrimaryController {
public Button primaryButton;
@FXML
private void switchToSecondary() throws IOException {
App.setRoot("secondary");
}
}
6. SecondaryController.java
package com.rockbb;
import java.io.IOException;
import javafx.fxml.FXML;
import javafx.scene.control.Button;
public class SecondaryController {
public Button secondaryButton;
@FXML
private void switchToPrimary() throws IOException {
App.setRoot("primary");
}
}
7. primary.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>
<VBox alignment="CENTER" spacing="20.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.rockbb.PrimaryController">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
</padding>
<Label text="Primary View"/>
<Button fx:id="primaryButton" text="Switch to Secondary View" onAction="#switchToSecondary"/>
</VBox>
8. secondary.fxml
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.VBox?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.control.Button?>
<?import javafx.geometry.Insets?>
<VBox alignment="CENTER" spacing="20.0" xmlns="http://javafx.com/javafx/8.0.171" xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.rockbb.SecondaryController">
<padding>
<Insets bottom="20.0" left="20.0" right="20.0" top="20.0"/>
</padding>
<Label text="Secondary View"/>
<Button fx:id="secondaryButton" text="Switch to Primary View" onAction="#switchToPrimary"/>
</VBox>
8. styles.css
.button {
-fx-text-fill: blue;
}
運行
IDEA中在App類上右鍵菜單, 點Run即可運行
打包發布
在JDK16之前, 可以使用jlink將項目打包為帶目錄結構的可執行文件, 在pom中修改javafx-maven-plugin的配置
<build>
<plugins>
...
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>${javafx.maven.plugin.version}</version>
<configuration>
<!-- 指定jlink路徑,如果你的系統中默認路徑是其他版本的jdk, 就必須用這個參數指定 -->
<jlinkExecutable>/opt/jdk/jdk-11.0.12/bin/jlink</jlinkExecutable>
<!-- 壓縮比例, 值可以為0,1,2, 默認為0 -->
<compress>2</compress>
<!-- Remove the includes directory in the resulting runtime image -->
<noHeaderFiles>true</noHeaderFiles>
<!-- Strips debug information out -->
<stripDebug>true</stripDebug>
<!-- Remove the man directory in the resulting Java runtime image -->
<noManPages>true</noManPages>
<!-- Add a launcher script -->
<launcher>launcher</launcher>
<!-- what main needs to be launched by specifying module, package and class -->
<mainClass>hellofx/com.rockbb.App</mainClass>
<!-- The name of the folder with the resulting runtime image -->
<jlinkImageName>hellofx</jlinkImageName>
<!-- When set, creates a zip of the resulting runtime image -->
<jlinkZipName>hellofx</jlinkZipName>
</configuration>
</plugin>
...
</plugins>
</build>
執行打包
clean compile javafx:jlink -f pom.xml
壓縮使用2時, 最終產生的lib/modules尺寸會明顯小很多, 這個並不一定體現到zip包的大小上, 2產生的zip包可能比0更大
在JDK16之后, 可以使用jpackage.