因此,我需要使用JavaFX线程来填充表视图,但是该表仅被填充了约70%的时间。我正在查看我的代码,但我真的找不到问题的出处,我的猜测是,在成功从db中检索/处理数据之前,任务正在以某种方式执行。谢谢是提前:)
private Executor exec;
private ObservableList<User> cellData = FXCollections.observableArrayList();
.
.
.
public void fillTable(HashMap<String,Object> whereClause){
Task<List<User>> task = new Task<List<User>>(){
@Override
public ObservableList<User> call(){
cellData.clear();
cellData.addAll(userRepository.getAll(whereClause));
userId.setCellValueFactory(new PropertyValueFactory<>("userID"));
userName.setCellValueFactory(new PropertyValueFactory<>("userName"));
userMail.setCellValueFactory(new PropertyValueFactory<>("userMail"));
userPhone.setCellValueFactory(new PropertyValueFactory<>("userPhone"));
isAdmin.setCellValueFactory(cellData -> {
String isAdminAsString = cellData.getValue().isAdmin() ? "Admin" : "Medic";
return new ReadOnlyStringWrapper(isAdminAsString);
});
isDeleted.setCellValueFactory(cellData -> {
String isActiveUser = cellData.getValue().isDeleted() ? "No" : "Yes";
return new ReadOnlyStringWrapper(isActiveUser);
});
logger.info("Cell values set");
return cellData;
}
};
exec.execute(task);
task.setOnFailed(e -> System.out.println(task.getException().getMessage()));
task.setOnSucceeded(e -> userTable.setItems((ObservableList<User>) task.getValue()));
logger.info("Fill user Table Task executed");
答案 0 :(得分:3)
您没有给出足够的上下文来给出正确,完全自信的答案,但是我的猜测是您遇到与线程有关的问题。 JavaFX不是线程安全的;使用错误的线程更新UI可能会导致未定义的行为,例如,数据仅在大约70%的时间出现。 JavaFX中有一个重要规则,您必须始终遵循以下规则:
您的代码不遵循此规则。在call
的{{1}}方法内部,您正在结构上修改Task
并设置各种cellData
的{{1}}。这导致所述对象被执行cellValueFactory
的任何线程修改。如果TableColumn
是任何提示,则该线程绝对不是 JavaFX Application线程。
我不确定为什么首先要在Task
方法中设置Executor
的{{1}}。单元格值工厂是仅需执行一次的配置-创建cellValueFactory
时(或之后不久)。换句话说,在TableColumn
方法中配置单元格值工厂是错误的,这不仅是因为它发生在后台线程上,而且还因为每次执行call
时都会发生。从TableColumn
方法中删除“设置单元格值工厂”代码,如果需要,将其移动到创建call
的位置。如果您使用的是FXML,并且为您创建了Task
并进行了注入,那么控制器的call
方法就是进行这种配置的好地方。
您的TableColumn
列表已连接到您的TableColumn
,如果不是第一次,则肯定是在第一次成功执行initialize
之后。在后台线程上修改cellData
将通知TableView
在同一线程上的那些更改(在进行更改的同一线程上调用侦听器)。一种简单的解决方案是让您的Task
返回一个 new cellData
,如果成功,则更新TableView
。
Task
List
的{{1}}方法将首先清除列表,然后添加给定集合(或数组)的所有元素。这比调用TableView
和后跟Task<List<User>> task = new Task<List<User>>() {
@Override protected List<User> call() throws Exception {
return userRepository.getAll(whereClause);
}
});
task.setOnSucceeded(event -> userTable.getItems().setAll(task.getValue()));
task.setOnFailed(event -> task.getException().printStackTrace());
exec.execute(task);
的效率更高,因为它只会导致一个更改事件。另外,如果您想继续使用setAll
,可以假设以前已将其设置为表格的项目;只需使用ObservableList
。
关于以下用途:
clear
由于您明确希望返回addAll
,因此应使用cellData
而不是cellData.setAll(task.getValue())
。这将意味着task.setOnSucceeded(e -> userTable.setItems((ObservableList<User>) task.getValue()));
返回ObservableList<User>
,因此不需要强制类型转换。但是,如果您按照上述建议进行操作,则无关紧要。