在 NetBeans 使用 JavaFX 時,常遇到如下錯誤 Error occurred during initialization of boot layer java.lang.module.FindException: Module javafx.fxml not found 表示啟動層初始化時 Java 執行環境無法找到 javafx.fxml 模組。 這可能是由於 NetBeans 模組路徑的設定錯誤 或 根本未安裝模組所致。 以下為診斷和解決這個問題的步驟。 1.檢查 JavaFX SDK 安裝 及 NetBeans 設定正確否 依據如下提示逐項檢查: how to set up NetBeans environment for JavaFX applications 2.打開 NetBeans 列印 Ant 腳本功能 依據如下設定選項 Tools/Options/Java/Ant 或者 NetBeans/Settings... Ant Home: ... [v] Always Show Output Verbosity Level: Quiet/Normal/[Verbose]/Debug 即可在執行 Run File 時,於 Output 視窗 觀看Ant Target (build.xml) Output 3.檢查 NetBeans 執行 Ant run 腳本的參數填對否 核對如下重要 java 執行參數 run: Executing '/path/to/bin/java' with arguments: '-Dfile.encoding=UTF-8' '--add-modules' 'javafx.controls,javafx.fxml,javafx.media' '-classpath' '/path/to/javafx-sdk-xx/lib/javafx-swt.jar: /path/to/javafx-sdk-xx/lib/javafx.base.jar: /path/to/javafx-sdk-xx/lib/javafx.controls.jar: /path/to/javafx-sdk-xx/lib/javafx.fxml.jar: /path/to/javafx-sdk-xx/lib/javafx.graphics.jar: /path/to/javafx-sdk-xx/lib/javafx.media.jar: /path/to/javafx-sdk-xx/lib/javafx.swing.jar: /path/to/javafx-sdk-xx/lib/javafx.web.jar: /path/to/MyProject/build/classes' '--module-path' '/path/to/MyProject/build/classes: /path/to/javafx-sdk-xx/lib/javafx-swt.jar: /path/to/javafx-sdk-xx/lib/javafx.base.jar: /path/to/javafx-sdk-xx/lib/javafx.controls.jar: /path/to/javafx-sdk-xx/lib/javafx.fxml.jar: /path/to/javafx-sdk-xx/lib/javafx.graphics.jar: /path/to/javafx-sdk-xx/lib/javafx.media.jar: /path/to/javafx-sdk-xx/lib/javafx.swing.jar: /path/to/javafx-sdk-xx/lib/javafx.web.jar' 'MyJavaFXApp' 4.任何一處 Ant run 腳本的參數有缺,可對應到如下 NetBeans 設定有誤: Project Properties Libraries/ Java Platform: JDK xx (Default) Compile/Compile-time Libraries: Classpath: JavaFX yy Run/Run-time Libraries: Modulepath: JavaFX yy Run/ Configuration: <default config> VM Options: --add-modules javafx.controls,javafx.fxml,javafx.media 註1: 其實 Ant build 及 run 腳本的工作原理就是由 NetBeans 設定抽取相關參數, 組合成如下命令列編譯及執行指令。故執行有問題可找回相關設定哪裏出問題。 命令列編譯指令 > javac -classpath "...\javafx-sdk-xx\lib\javafx.fxml.jar;...;." \ MyJavaFXApp.java 命令列執行指令 > java --add-modules javafx.controls,javafx.fxml,javafx.media \ -classpath . \ --module-path "...\javafx-sdk-xx\lib\javafx.fxml.jar;..." \ MyJavaFXApp 註2: NetBeans 執行 Ant run 腳本時,依序參考如下檔案 MyProject/ build.xml nbproject/ build-impl.xml project.properties 其中,project.properties有專案屬性如下,存放設定執行參數,亦可對照檢視設定錯誤原因。 run.classpath=\ ${javac.classpath}:\ ${build.classes.dir} run.jvmargs=--add-modules javafx.controls,javafx.fxml,javafx.media run.modulepath=\ ${javac.modulepath}:\ ${libs.JavaFX_xx.classpath}
seke blog
2024年12月11日 星期三
Diagnosing the Error: Module javafx.fxml not found
2024年12月10日 星期二
Two ways to draw shapes in JavaFX
JavaFX 有 2 種畫形狀的寫法如下: A. Pane容器放 Shape 形狀import javafx.scene.layout.Pane; import javafx.scene.paint.Color; import javafx.scene.shape.Circle; import javafx.scene.shape.Rectangle; .... Pane pane = new Pane(); Circle circle = new Circle(50, 50, 30); circle.setFill(Color.BLUE); Rectangle rectangle = new Rectangle(100, 100, 80, 40); rectangle.setFill(Color.RED); pane.getChildren().addAll(circle, rectangle);
註1: Pane小孩清單會記住所有加入形狀元件,Pane大小調整後也會重新顯示所有形狀 註2: javafx.scene.shape支援形狀有 Circle, Rectangle, Ellipse, Line, Polygon, Polyline, Arc, CubicCurve, QuadCurve, Path 等 B. Canvas元件上畫出形狀import javafx.scene.canvas.Canvas; import javafx.scene.canvas.GraphicsContext; import javafx.scene.paint.Color; ..... Canvas canvas = new Canvas(300, 200); GraphicsContext gc = canvas.getGraphicsContext2D(); gc.setFill(Color.BLUE); gc.fillOval(50, 50, 60, 60); // Draw a circle gc.setFill(Color.RED); gc.fillRect(150, 100, 80, 40); // Draw a rectangle
註1: javafx.scene.canvas.GraphicsContext會暫時記住所有畫圖區內容,直到大小異動才清空 註2: javafx.scene.canvas.GraphicsContext支援形狀有 // 矩形 fillRect(double x, double y, double w, double h) // 前景色填滿 strokeRect(double x, double y, double w, double h) // 前景色畫框 clearRect(double x, double y, double w, double h) // 背景色填滿 // 圓形 fillOval(double x, double y, double w, double h) strokeOval(double x, double y, double w, double h) // 弧形 fillArc(double x, double y, double w, double h, double startAngle, double arcExtent, ArcType closure) strokeArc(double x, double y, double w, double h, double startAngle, double arcExtent, ArcType closure) // 多邊形,多邊線 fillPolygon(double[] xPoints, double[] yPoints, int nPoints) strokePolygon(double[] xPoints, double[] yPoints, int nPoints) fillPolyline(double[] xPoints, double[] yPoints, int nPoints) strokePolyline(double[] xPoints, double[] yPoints, int nPoints) strokeLine(double x1, double y1, double x2, double y2) // 路徑模式, 一次只能維護一條路徑 beginPath() moveTo(double x, double y) lineTo(double x, double y) closePath() stroke() // 畫路徑框 fill() // 畫路徑內部
2024年12月1日 星期日
how to write change event handlers for JavaFX components
在 javafx.scene.control 套件路徑下,如下元件有更動屬性都會產生異動事件(Change Event), TextField/CheckBox/ComboBox/RadioButton/ChoiceBox/Slider/ListView 可對元件屬性註冊異動事件處理器(Change Event Handler),接收異動事件,進行處理。 註冊異動事件處理器寫法,和註冊動作事件處理器寫法不同, 須利用.xxxProperty()方法先取得元件屬性, 再利用.addListener 方法為屬性添加異動監聽器,寫法如下:textField.textProperty().addListener((observable, oldValue, newValue) -> { System.out.println("value changed from " + oldValue + " to " + newValue); });
或textField.textProperty().addListener(new ChangeListener<String>() { @Override public void changed(ObservableValue observable, String oldValue, String newValue) { System.out.println("value changed from " + oldValue + " to " + newValue); } });
註1: 至於其他元件的異動事件處理器註冊,須搭配各元件的屬性取法不同,寫法如下: checkBox.selectedProperty().addListener(...) comboBox.valueProperty().addListener(...) radioButton.selectedProperty().addListener(...) choiceBox.getSelectionModel().selectedItemProperty().addListener(...) slider.valueProperty().addListener(...) listView.getSelectionModel().selectedItemProperty().addListener(...) 註2: JavaFX 有 javafx.event.ActionEvent 動作事件類別及物件,但沒有異動事件類別。 元件一旦有動作事件,通常屬於高階離散事件,立即一次性處理完即可, 故設計上註冊處理器寫法較簡單,只允許對元件呼叫如下方法,掛上單一動作監聽器。 setOnAction(event -> {...}); 註3: 元件屬性一旦有異動事件,通常屬於低階連續事件,須要密集多次處理狀態變化, 故設計上註冊處理器寫法較細緻彈性,可對屬性呼叫如下方法,掛上多個異動監聽器。 addListener( new javafx.beans.value.ChangeListener( (ob, oldV, newV) -> {...} ) );
Two ways to write action event handlers in JavaFX
在 javafx.scene.control 套件路徑下,如下元件受點選都會產生動作事件(ActionEvent), Button/TextField/CheckBox/ComboBox/RadioButton/MenuItem/Hyperlink 可對元件註冊動作事件處理器(ActionEvent Handler),接收動作事件,進行處理。 註冊動作事件處理器有兩種寫法: 1.利用元件的.setOnAction方法註冊,寫法如下button.setOnAction(event -> System.out.println("Button clicked!"));
或button.setOnAction(new EventHandler<ActionEvent>() { @Override public void handle(ActionEvent event) { System.out.println("Button clicked!"); } });
2. 利用.fxml檔的元件屬性註冊,寫法如下 <Button text="Click Me" onAction="#handleButtonAction"/>public class Controller { @FXML private void handleButtonAction(ActionEvent event) { System.out.println("Button clicked!"); } }
註: 方法前的 @ 標註旨在通知編譯器作防呆檢查,減少可能錯誤 1. @Override 標註將提醒編譯器檢查該方法簽名是否有覆蓋上一代方法 2. @FXML 標註將提醒編譯器檢查該方法或屬性是否出現於 .fxml 介面配置檔中
2024年11月30日 星期六
How to interpret the caused by sections of a Java stack trace?
Java執行出錯丟出例外時,常會列印一串 Caused by 訊息,其格式為 java.lang.Exception: Exception in xxx at ......... (....java: ..) ....... at ......... (....java: ..) Caused by: java.lang.Exception: Exception in yyy at ......... (....java: ..) ....... at ......... (....java: ..) Caused by: java.lang.Exception: Exception in zzz at ......... (....java: ..) ....... at ......... (....java: ..)
這表示先有 zzz 錯誤,然後造成 yyy 錯誤,然後造成 xxx 錯誤。因此,最初錯誤原因為最後Caused by 指出的 zzz 錯誤。至於每個錯誤後面都會跟著很多 at,印出丟出例外當時的方法堆疊內容,越後面的 at 程式碼越早執行。
public class CausedByExample {
public static void main(String[] args) {
try {
method1(); // line 4
} catch (Exception e) {
// 此行指令表明 執行方法main出現例外 將列印丟出例外時的堆疊記錄內容
e.printStackTrace();
}
}
public static void method1() throws Exception {
try {
method2(); // line 13
} catch (Exception e) {
// 此行指令表明 執行方法1出現例外 是由 執行方法2的例外e 所造成,將列印
// java.lang.Exception: Exception in method1
// 逐層列印丟出方法1例外時的堆疊記錄內容
throw new Exception("Exception in method1", e); // line 18
// public Exception(String message, Throwable cause)
// 產生新例外,包含例外說明字串 message,及造成本例外的原因 cause
}
}
public static void method2() throws Exception {
// 此行指令表明 執行方法2出現例外,將列印
// java.lang.Exception: Exception in method2
// 逐層列印丟出方法2例外時的堆疊記錄內容
throw new Exception("Exception in method2"); // line 26
}
}
Output:
上面程式在method2產生例外,由method1接收,再包裝成原因產生新例外,由main接收,列印e.printStackTrace。其列印內容說明,Exception in method2 造成 Exception in method1。
java.lang.Exception: Exception in method1
at CausedByExample.method1(CausedByExample.java:18)
at CausedByExample.main(CausedByExample.java:4)
Caused by: java.lang.Exception: Exception in method2
at CausedByExample.method2(CausedByExample.java:26)
at CausedByExample.method1(CausedByExample.java:13)
... 1 more
2024年11月12日 星期二
how to set up NetBeans environment for JavaFX applications
JavaFX 為 Java 繼 Awt, Swing 之後推出的第 3 代圖形介面 (GUI) 套件,多了場景建立器 (Scene Builder),排版配置檔 CSS 等支援能力。 利用 NetBeans 整合開發環境 (IDE) 撰寫 JavaFX 應用時,常遇到開發環境如何建立的問題。很容易會遇到如下錯誤:
Error occurred during initialization of boot layer
java.lang.module.FindException: Module javafx.controls not found
或
java.lang.module.FindException: Module javafx.fxml not found
以下整理幾點 NetBeans 整合 JavaFX SDK,SceneBuilder 場景建立器,詳查 Build 腳本的方法,供除錯參考。
✅ NetBeans 整合 JavaFX SDK 方法 Project Properties Libraries/ Java Platform: JDK xx (Default) Compile/Compile-time Libraries: Classpath: JavaFX yy Run/Run-time Libraries: Modulepath: JavaFX yy Run/ Configuration: <default config> VM Options: --add-modules javafx.controls,javafx.fxml,javafx.media ✅ NetBeans 整合 SceneBuilder 方法 Tools/Options/Java/JavaFX JavaFX Scene Builder Integration Scene Builder Home: C:\Users\zz\AppData\Local\SceneBuilder ✅ NetBeans除錯想看Build執行腳本內容 Tools/Options/Java/Ant: Ant Home: ... [v] Always Show Output Verbosity Level: Quiet/Normal/[Verbose]/Debug 即可觀看Ant Target (build.xml) Output 註1: 建立 JavaFX 開發環境所須安裝套件如下 1.OpenJDK https://learn.microsoft.com/zh-tw/java/openjdk/download microsoft-jdk-21.0.5-windows-x64.msi (不含JavaFX) microsoft-jdk-21.0.5-macos-aarch64.pkg https://www.azul.com/downloads/?package=jdk-fx#zulu zulu21.38.21-ca-fx-jdk21.0.5-win_x64.msi (含JavaFX) 2.NetBeans https://netbeans.apache.org/download/index.html Apache-NetBeans-22-bin-windows-x64.exe Apache-NetBeans-22.pkg 3.SceneBuilder https://gluonhq.com/products/scene-builder/ SceneBuilder-23.0.1.msi SceneBuilder-23.0.1-aarch64.dmg 4.JavaFX SDK https://gluonhq.com/products/javafx/ openjfx-17.0.13_windows-x64_bin-sdk.zip openjfx-17.0.13_osx-aarch64_bin-sdk.zip 註2: NetBeans 要看到 Scene Builder Home,須要安裝且啟動(Activate)如下任一插件 Tools/Plugins: JavaFX 2 或 JavaFX Implementation for Windows 安裝之後,針對專案 .fxml 按右鍵,才會看到如下選項 Open 連動開啟場景建立器畫面 Edit 開啟.fxml文字畫面 Make Controller 產生 .fxml 中 fx:controller 屬性指定的控制器.java類別檔 註3: NetBeans 要能看到 JavaFX yy 類別庫,須設定 Tools/Libraries/Libraries: Library Name: JavaFX yy Classpath/Add JAR/Folder...: ...\javafx-sdk-yy\lib\javafx-swt.jar ...\javafx-sdk-yy\lib\javafx.base.jar ...\javafx-sdk-yy\lib\javafx.controls.jar ...\javafx-sdk-yy\lib\javafx.fxml.jar ...\javafx-sdk-yy\lib\javafx.graphics.jar ...\javafx-sdk-yy\lib\javafx.media.jar ...\javafx-sdk-yy\lib\javafx.swing.jar ...\javafx-sdk-yy\lib\javafx.web.jar 註4: NetBeans 要能點選原始碼類別,按右鍵點選 Show Javadoc (Alt-F1) 看到類別 註解說明,須設定 Tools/Libraries/Libraries: Library Name: JavaFX yy Javadoc/Add URL...: https://docs.oracle.com/javafx/2/api/ 註5: NetBeans 要能點選原始碼類別,按右鍵點選 Navigate> Go to Source (Ctrl-Shift-B) 看到類別 原始碼,須設定 Tools/Libraries/Libraries: Library Name: JavaFX yy Sources/Add JAR/Folder...: ...\javafx-sdk-yy\src.zip
2024年11月11日 星期一
controller class not found or fxml load error when running JavaFX applications
執行 JavaFX 圖形介面程式,使用視窗配置檔 .fxml 時,若出現 fxml載入錯誤 或 控制器類別找不到 錯誤,很可能是因為 .fxml 配置檔的控制器指定值沒有寫對。可打開 .fxml 檔,檢查容器 (XXPane) 標籤的 fx:controller 控制器欄位值是否正確。若有使用套件包裝,其套件路徑是否正確。
如下 fxml 配置檔範例中,假設 DrawShapesController.java 控制器宣告歸屬套件 package com.abc;,則其值前面要加上 com.abc 套件路徑,在依據 fxml 配置檔載入控制器時,才找得到控制器類別。
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity"
minHeight="-Infinity" minWidth="-Infinity"
xmlns="http://javafx.com/javafx/8.0.60"
xmlns:fx="http://javafx.com/fxml/1"
fx:controller="com.abc.DrawShapesController">
...
</BorderPane
>
註1: 常見 fxml載入錯誤 及 控制器類別找不到錯誤 例子。
Exception in Application start method
java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
.....
at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: Exception in Application start method
at javafx.graphics@19/.....LauncherImpl.launchApplication1(LauncherImpl.java:901)
at javafx.graphics@19/.....LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:196)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: javafx.fxml.LoadException: ..../DrawShapes.fxml:8
at javafx.fxml@19/javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2707)
......
at ......DrawShapes.start(DrawShapes.java:16)
......
Caused by: java.lang.ClassNotFoundException: DrawShapesController
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:583)
......
Exception running application .....DrawShapes
註2: 有時也會看到如下 找不到類別定義錯誤 例子。
Caused by: java.lang.NoClassDefFoundError: DrawRandomLinesController (wrong name: DrawRandomLinesController)