PropertyValueFactory 错误 getter 来自模型 class
PropertyValueFactory error on proper getter from model class
我正在尝试从 fxml 文件填充示例 javafx TableView。
这是我的控制器方法:
public class TestController implements Initializable {
@FXML private TableView<user> tableView;
@FXML private TableColumn<user, String> UserId;
@FXML private TableColumn<user, String> UserName;
public void initialize(URL location, ResourceBundle resources) {
UserId.setCellValueFactory(new PropertyValueFactory<user, String>("userId"));
UserName.setCellValueFactory(new PropertyValueFactory<user, String>("userName"));
tableView.getItems().setAll(parseUserList());
}
private List<user> parseUserList(){
List<user> l_u = new ArrayList<user>();
user u = new user();
u.setUserId(1);
u.setUserName("test1");
l_u.add(u);
u.setUserId(2);
u.setUserName("test2");
l_u.add(u);
u.setUserId(3);
u.setUserName("test3");
l_u.add(u);
return l_u;
}
}
和 fxml 文件:
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="369.0" prefWidth="505.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="viewmodel.TestController ">
<center>
<TableView fx:id="tableView" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<columns>
<TableColumn prefWidth="75.0" text="UserId" fx:id="UserId"/>
<TableColumn prefWidth="75.0" text="UserName" fx:id="UserName"/>
</columns>
</TableView>
</center>
</BorderPane>
最后是我的模型:
封装模型;
public class user {
private int userId;
public int getUserId() { return this.userId; }
public void setUserId(int userId) { this.userId = userId; }
private String userName;
public String getUserName() { return this.userName; }
public void setUserName(String userName) { this.userName = userName; }
}
现在,当我尝试填充它时,出现了这个错误:
Jun 28, 2019 12:17:35 PM javafx.scene.control.cell.PropertyValueFactory getCellDataReflectively
WARNING: Can not retrieve property 'userId' in PropertyValueFactory: javafx.scene.control.cell.PropertyValueFactory@638db851 with provided class type: class model.user
java.lang.RuntimeException: java.lang.IllegalAccessException: module javafx.base cannot access class model.user (in module JavaFXTest) because module JavaFXTest does not open model to javafx.base
at javafx.base/com.sun.javafx.property.PropertyReference.get(PropertyReference.java:176)
SO 上的一些文章提到,getter 和 setter 属性 必须在 get word 后以大写字母开头,但这并没有解决问题。
这是一个很好的例子来说明“为什么你应该使用 Callback
而不是 PropertyValueFactory
。目前我看不出有任何理由使用 PVF 而不是回调。
在这里您可以看到一个缺点,即您在 运行 应用程序之前并没有真正看到自己犯了编码错误。
由于 PVF 使用反射,如果您没有正确声明它们,它就找不到合适的字段。正如您在异常中看到的那样,PVF 期望 Property
-es
PropertyRefference
是必需的,user
class 中声明的字段 none 是 Property
es
它可以这样使用,但是你必须重写 user
class 像:
public class User { // use java naming conventions
private IntegerProperty userId;
public int getUserId() { return this.userId.get(); }
public void setUserId(int userId) { this.userId.set(userId); }
public IntegerProperty userIdProperty() { return this.userId; }
private StringProperty userName;
public String getUserName() { return this.userName.get(); }
public void setUserName(String userName) { this.userName.set(userName); }
public StringProperty userNameProperty() {return this.userName; }
public User(int userId,String userName){
this.userId = new SimpleIntegerProperty(userId);
this.userName = new SimpleStringProperty(userName);
}
}
现在,由于字段是属性,PropertyValueFactory 会找到它们但是我不建议使用它,因为正如您所看到的,它会导致您甚至无法解决的问题在你运行之前注意它。
所以不是:
UserId.setCellValueFactory(new PropertyValueFactory<user, String>("userId"));
UserName.setCellValueFactory(new PropertyValueFactory<user, String>("userName"));
使用:
// use java naming conventions (`userId` instead of `UserId`)
userId.setCellValueFactory(data -> data.getValue().userIdProperty().asString());
// same here user naming convention
userName.setCellValueFactory(data -> data.getValue().userNameProperty());
我已经写过几次评论了,但我会在这里再次提到它使用java命名约定。像 User 而不是 user 和 userId 而不是 UserId 等等...
虽然违反 java 命名约定(始终遵循它们!)和 PropertyValueFactory 的不当使用(如果没有令人信服的理由,请不要使用它!)是常见的嫌疑人,但他们似乎没有成为OP问题的原因。
错误消息表明问题出现在模块化上下文中:
Jun 28, 2019 12:17:35 PM javafx.scene.control.cell.PropertyValueFactory getCellDataReflectively
WARNING: Can not retrieve property 'userId' in PropertyValueFactory:
javafx.scene.control.cell.PropertyValueFactory@638db851 with provided class type: class model.user
java.lang.RuntimeException: java.lang.IllegalAccessException:
module javafx.base cannot access class model.user (in module JavaFXTest)
because module JavaFXTest does not open model to javafx.base
实际上,该示例在 non-modular 上下文中运行良好,但在模块化时失败。错误消息准确地告诉我们该怎么做:打开我们的模块(或其中的一部分)进行反射访问。
Module-info 打开完整模块或单个包:
// complete
open module JavaFXTest {
exports ourpackage;
...
}
// parts
module JavaFXTest {
exports ourpackage;
opens ourpackage.model;
}
我正在尝试从 fxml 文件填充示例 javafx TableView。
这是我的控制器方法:
public class TestController implements Initializable {
@FXML private TableView<user> tableView;
@FXML private TableColumn<user, String> UserId;
@FXML private TableColumn<user, String> UserName;
public void initialize(URL location, ResourceBundle resources) {
UserId.setCellValueFactory(new PropertyValueFactory<user, String>("userId"));
UserName.setCellValueFactory(new PropertyValueFactory<user, String>("userName"));
tableView.getItems().setAll(parseUserList());
}
private List<user> parseUserList(){
List<user> l_u = new ArrayList<user>();
user u = new user();
u.setUserId(1);
u.setUserName("test1");
l_u.add(u);
u.setUserId(2);
u.setUserName("test2");
l_u.add(u);
u.setUserId(3);
u.setUserName("test3");
l_u.add(u);
return l_u;
}
}
和 fxml 文件:
<BorderPane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="369.0" prefWidth="505.0" xmlns="http://javafx.com/javafx/11.0.1" xmlns:fx="http://javafx.com/fxml/1" fx:controller="viewmodel.TestController ">
<center>
<TableView fx:id="tableView" prefHeight="200.0" prefWidth="200.0" BorderPane.alignment="CENTER">
<columns>
<TableColumn prefWidth="75.0" text="UserId" fx:id="UserId"/>
<TableColumn prefWidth="75.0" text="UserName" fx:id="UserName"/>
</columns>
</TableView>
</center>
</BorderPane>
最后是我的模型:
封装模型;
public class user {
private int userId;
public int getUserId() { return this.userId; }
public void setUserId(int userId) { this.userId = userId; }
private String userName;
public String getUserName() { return this.userName; }
public void setUserName(String userName) { this.userName = userName; }
}
现在,当我尝试填充它时,出现了这个错误:
Jun 28, 2019 12:17:35 PM javafx.scene.control.cell.PropertyValueFactory getCellDataReflectively
WARNING: Can not retrieve property 'userId' in PropertyValueFactory: javafx.scene.control.cell.PropertyValueFactory@638db851 with provided class type: class model.user
java.lang.RuntimeException: java.lang.IllegalAccessException: module javafx.base cannot access class model.user (in module JavaFXTest) because module JavaFXTest does not open model to javafx.base
at javafx.base/com.sun.javafx.property.PropertyReference.get(PropertyReference.java:176)
SO 上的一些文章提到,getter 和 setter 属性 必须在 get word 后以大写字母开头,但这并没有解决问题。
这是一个很好的例子来说明“为什么你应该使用 Callback
而不是 PropertyValueFactory
。目前我看不出有任何理由使用 PVF 而不是回调。
在这里您可以看到一个缺点,即您在 运行 应用程序之前并没有真正看到自己犯了编码错误。
由于 PVF 使用反射,如果您没有正确声明它们,它就找不到合适的字段。正如您在异常中看到的那样,PVF 期望 Property
-es
PropertyRefference
是必需的,user
class 中声明的字段 none 是 Property
es
它可以这样使用,但是你必须重写 user
class 像:
public class User { // use java naming conventions
private IntegerProperty userId;
public int getUserId() { return this.userId.get(); }
public void setUserId(int userId) { this.userId.set(userId); }
public IntegerProperty userIdProperty() { return this.userId; }
private StringProperty userName;
public String getUserName() { return this.userName.get(); }
public void setUserName(String userName) { this.userName.set(userName); }
public StringProperty userNameProperty() {return this.userName; }
public User(int userId,String userName){
this.userId = new SimpleIntegerProperty(userId);
this.userName = new SimpleStringProperty(userName);
}
}
现在,由于字段是属性,PropertyValueFactory 会找到它们但是我不建议使用它,因为正如您所看到的,它会导致您甚至无法解决的问题在你运行之前注意它。
所以不是:
UserId.setCellValueFactory(new PropertyValueFactory<user, String>("userId"));
UserName.setCellValueFactory(new PropertyValueFactory<user, String>("userName"));
使用:
// use java naming conventions (`userId` instead of `UserId`)
userId.setCellValueFactory(data -> data.getValue().userIdProperty().asString());
// same here user naming convention
userName.setCellValueFactory(data -> data.getValue().userNameProperty());
我已经写过几次评论了,但我会在这里再次提到它使用java命名约定。像 User 而不是 user 和 userId 而不是 UserId 等等...
虽然违反 java 命名约定(始终遵循它们!)和 PropertyValueFactory 的不当使用(如果没有令人信服的理由,请不要使用它!)是常见的嫌疑人,但他们似乎没有成为OP问题的原因。
错误消息表明问题出现在模块化上下文中:
Jun 28, 2019 12:17:35 PM javafx.scene.control.cell.PropertyValueFactory getCellDataReflectively
WARNING: Can not retrieve property 'userId' in PropertyValueFactory:
javafx.scene.control.cell.PropertyValueFactory@638db851 with provided class type: class model.user
java.lang.RuntimeException: java.lang.IllegalAccessException:
module javafx.base cannot access class model.user (in module JavaFXTest)
because module JavaFXTest does not open model to javafx.base
实际上,该示例在 non-modular 上下文中运行良好,但在模块化时失败。错误消息准确地告诉我们该怎么做:打开我们的模块(或其中的一部分)进行反射访问。
Module-info 打开完整模块或单个包:
// complete
open module JavaFXTest {
exports ourpackage;
...
}
// parts
module JavaFXTest {
exports ourpackage;
opens ourpackage.model;
}