JavaFX含TableView的场景无法通过按钮打开的问题排查
JavaFX TableView场景加载失败问题解决
问题描述
使用JavaFX开发学生信息录入桌面应用,初始场景的切换按钮可正常访问其他场景,但包含从数据库加载学生信息的TableView的场景无法打开,报错信息如下。
报错信息
javafx.fxml.LoadException: /H:/Java/Educational%20Centre/target/classes/com/example/educationalcentre/Table.fxml:10 at javafx.fxml@20.0.1/javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2722) at javafx.fxml@20.0.1/javafx.fxml.FXMLLoader$InstanceDeclarationElement.constructValue(FXMLLoader.java:1024) ... Caused by: java.lang.ClassNotFoundException: com.sun.javafx.collections.MappingChange$Map at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641) ...
相关代码
Table.fxml
<?xml version="1.0" encoding="UTF-8"?> <?import javafx.scene.control.*?> <?import javafx.scene.layout.*?> <?import javafx.scene.text.*?> <AnchorPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/17.0.2-ea" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.example.educationalcentre.TableController"> <TableView fx:id="tblStudent" layoutY="70.0" prefHeight="321.0" prefWidth="600.0"> <columns> <TableColumn fx:id="id" prefWidth="75.0" text="StudentID"/> <TableColumn fx:id="fname" prefWidth="75.0" text="First Name"/> <TableColumn fx:id="lname" prefWidth="75.0" text="Last Name"/> <TableColumn fx:id="gender" prefWidth="75.0" text="Gender"/> <TableColumn fx:id="email" prefWidth="75.0" text="Email"/> <TableColumn fx:id="dob" prefWidth="75.0" text="BirthDay"/> <TableColumn fx:id="cstatus" prefWidth="75.0" text="Civil Status"/> <TableColumn fx:id="address" prefWidth="75.0" text="Address"/> </columns> </TableView> <Label layoutX="9.0" layoutY="9.0" prefHeight="46.0" prefWidth="339.0" text="Student List"> <font> <Font size="35.0"/> </font> </Label> </AnchorPane>
TableController.java
package com.example.educationalcentre; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.control.cell.PropertyValueFactory; import javafx.fxml.Initializable; import java.net.URL; import java.sql.SQLException; import java.util.Date; import java.util.ResourceBundle; public class TableController implements Initializable { StudentService studentService; @FXML private TableView <Student> tblStudent; @FXML private TableColumn <Student, Integer> id; @FXML private TableColumn <Student,String> fname; @FXML private TableColumn <Student,String> lname; @FXML private TableColumn <Student,String> gender; @FXML private TableColumn <Student,String> email; @FXML private TableColumn <Student, Date> dob; @FXML private TableColumn <Student,String> cstatus; @FXML private TableColumn <Student, String> address; @Override public void initialize(URL url, ResourceBundle resourceBundle) { try { loadStudent(); } catch (SQLException | ClassNotFoundException e) { throw new RuntimeException(e); } } @FXML private void loadStudent() throws SQLException, ClassNotFoundException { studentService = new StudentService(); ObservableList<Student> students; students = FXCollections.observableArrayList(studentService.getStudentList()); id.setCellValueFactory(new PropertyValueFactory<Student, Integer>("studentID")); fname.setCellValueFactory(new PropertyValueFactory<Student, String>("firstName")); lname.setCellValueFactory(new PropertyValueFactory<Student, String>("lastName")); address.setCellValueFactory(new PropertyValueFactory<Student, String>("address")); email.setCellValueFactory(new PropertyValueFactory<Student, String>("email")); cstatus.setCellValueFactory(new PropertyValueFactory<Student, String>("civilStatus")); gender.setCellValueFactory(new PropertyValueFactory<Student, String>("gender")); dob.setCellValueFactory(new PropertyValueFactory<Student, Date>("DOB")); tblStudent.setItems(students); }
场景切换方法代码
@FXML public void switchToTable(ActionEvent event) throws IOException { FXMLLoader fxmlLoader = new FXMLLoader(RegistryApplication.class.getResource("Table.fxml")); stage = (Stage) ((Node)event.getSource()).getScene().getWindow(); try { scene = new Scene(fxmlLoader.load()); } catch (IOException e) { e.printStackTrace(); throw new RuntimeException(e); } stage.setScene(scene); stage.show(); }
解决方案
1. 统一JavaFX版本
报错显示运行时使用JavaFX 20.0.1,但FXML文件的命名空间指定的是17.0.2-ea,版本不匹配导致内部API路径错误。将项目依赖的JavaFX版本和运行时版本统一,比如都使用20.0.1或17.x LTS版本(推荐LTS版本更稳定)。
2. 修改FXML命名空间
将Table.fxml中的命名空间xmlns="http://javafx.com/javafx/17.0.2-ea"修改为与当前JavaFX版本一致的地址,例如:
- 若使用20.0.1,改为
xmlns="http://javafx.com/javafx/20" - 若使用17.x,改为
xmlns="http://javafx.com/javafx/17"
如果使用构建工具(Maven/Gradle),可以用动态变量匹配版本,比如xmlns="http://javafx.com/javafx/${javafx.version}"。
3. 验证Student类的JavaBean规范
确保Student类的属性名与PropertyValueFactory中传入的参数一致,并且每个属性都有对应的getter方法:
- 例如
studentID对应getStudentID(),firstName对应getFirstName(),DOB对应getDOB(),否则PropertyValueFactory无法正确读取属性值。
4. 优化异常处理
不要在initialize方法中直接抛出RuntimeException,改为捕获异常并给用户友好提示,比如:
@Override public void initialize(URL url, ResourceBundle resourceBundle) { try { loadStudent(); } catch (SQLException | ClassNotFoundException e) { e.printStackTrace(); Alert alert = new Alert(Alert.AlertType.ERROR); alert.setTitle("加载失败"); alert.setHeaderText("无法加载学生信息"); alert.setContentText("请检查数据库连接或重试"); alert.showAndWait(); } }
内容的提问来源于stack exchange,提问作者vchandu
相关产品推荐
相关产品推荐

