JavaFX-从任务更新表行

JavaFX-从任务更新表行,java,javafx,Java,Javafx,我试图从JavaFx任务内部更新表中的文本。我以前用基本标签做过这项工作,但当涉及到正确绑定到表和更新行时,我完全不知所措。这是我到目前为止的代码 我的主课 public class AnotherClass extends Application { static List<Listing> listings = Collections.synchronizedList(new ArrayList<Listing>()); @Override public vo

我试图从JavaFx任务内部更新表中的文本。我以前用基本标签做过这项工作,但当涉及到正确绑定到表和更新行时,我完全不知所措。这是我到目前为止的代码

我的主课

public class AnotherClass extends Application {
static List<Listing> listings = Collections.synchronizedList(new ArrayList<Listing>());
@Override
    public void start(Stage stage) throws Exception {
        // calls init function about 200 lines of code for adding Listing objects to the listings list.

        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));

        Scene scene = new Scene(root);

        stage.setScene(scene);
        stage.show();

    }
}
然后我有一个任务需要更新表

public class UpdateTableTask extends Service<Void>{

@Override
protected Task<Void> createTask() {
        return new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                  while(true){
                       synchronized(AnotherClass.listings){
                          for(int i = 0; i < AnotherClass.listings.size(); i++){
                              // multiple threads access the list.
                               Response response = makeAPICall();
                              listings.get(i).isCompetitive(response); //true or false
                              Thread.sleep(1000);
                          }

                       }
                  }

            }
        }
    }
}
public类UpdateTableTask扩展服务{
@凌驾
受保护的任务createTask(){
返回新任务(){
@凌驾
受保护的Void调用()引发异常{
while(true){
已同步(另一个class.listings){
对于(int i=0;i
(手动输入代码)


任何帮助都将不胜感激。谢谢

这有点困难,因为您的代码有点不完整,实际上无法编译,所以我将稍微修改一些内容并做出一些假设(可能与您的实际用例不匹配)

假设您想要一个列:

@FXML
TableColumn<Listing, String> isCompetitiveCol;
写:

private BooleanProperty isCompetitive = new SimpleBooleanProperty(true);
public void setIsCompetitive(boolean isCompetitive){
    this.isCompetitive.set(isCompetitive);
}
public boolean getIsCompetitive(){
    return this.isCompetitive.get(); 
}
public BooleanProperty isCompetitiveProperty() {
    return isCompetitive;
}
这会将competitive属性转换为可侦听属性,当其值更新时,可以触发更改和无效侦听器。每当属性发生更改时,实现将触发更新通知(以及对表中单元格中的值的后续更新)

在使用线程时,需要确保不更新JavaFX应用程序线程的isCompetitive属性值(因为属性更新触发的场景图更新只能在JavaFX应用程序线程上发生)。您可以通过使用运行任何更新来做到这一点

因此,您的任务可以是这样的:

@FXML
public TableView<Listing> allListings; 
...
for(int i = 0; i < AnotherClass.listings.size(); i++){
    allListingsData.add(new Listing(AnotherClass.listings.get(i))); 
}
...
return new Task<Void>() {
    @Override
    protected Void call() throws Exception {
         while(true){
              synchronized(AnotherClass.listings) {
                  for(int i = 0; i < AnotherClass.listings.size(); i++){
                      Response response = makeAPICall();
                      Platform.runLater(() -> {
                          allListings.getItems().get(i).setIsCompetitive(
                              response.isCompetitive()
                          );
                      }; 
                      Thread.sleep(1000);
                  }
              }
         }
    }
}
@FXML
公共表查看所有列表;
...
对于(int i=0;i{
allListings.getItems().get(i).setIsCompetitive(
response.isCompetitive()
);
}; 
睡眠(1000);
}
}
}
}
}
注意,我将TableView项目中的列表对象与
AnotherClass.listings
类中的列表对象分开(通过使用
allListingsData.add创建列表(新列表(AnotherClass.listings.get(I));
)。这是为了确保当您有其他线程更新另一个类.listings
值时,不会产生通过PropertyValueFactory建立的链接尝试更新表的副作用。相反,更新会从另一个类.listings传输到platform.runLater ca中的TableView我将确保表格仅在需要更改时更改

注:上述解决方案假设一个固定的列表,其中列表属性的值发生变化,但列表本身的数量和顺序不会发生变化(例如,在此过程中列表不会添加、删除或重新排序)。如果该假设不成立,那么您将需要额外的逻辑来更新列表值本身,而不仅仅是列表元素中的属性(并且在不违反线程规则的情况下小心这样做)。要了解如何实现这一点,您可以查看有关返回可观察列表的任务、部分结果任务和修改场景图的任务的部分,并且可能需要使用这些示例中描述的习惯用法的一些组合来实现所需的结果


另外请注意,因为您只是在任务中执行
而(true)
,所以您甚至可能不需要任务(因为您没有使用它的任何功能,例如返回值、updateMessage和updateProgress系统)。相反,您可以只启动具有可运行的线程(新线程()或使用执行器)并根据需要通过Platform.runLater更新值。

为什么这是在后台线程中?您需要在FX应用程序线程上执行实际更新。若要更新,您只需在相应的
列表
实例上调用某个方法,假设您的
列表
类使用JavaFX属性。该线程会遇到APIy秒并更新列表对象的列表。这就是为什么它在线程中。我希望它直接从线程更新,这样,如果某一行上的数据响应出现问题,我也可以显示错误消息。我的列表类只包含getter和setter。如果不使用JavaFX属性,则必须使用c所有
allListings.refresh()
更改
Listing
对象后(通过调用相应的
set
方法)。这将是非常低效的。如果您使用JavaFX属性,则不需要这样做,相应的单元格将做出响应。无论如何,基本上您只需要在FX应用程序线程上设置
列表
对象的值(使用
平台.runLater()
).你能展示一下你所做的吗?如果不看你所做的,就不可能知道为什么它不起作用。我还没有真正尝试过任何东西
isCompetitiveCol.setCellValueFactory(new PropertyValueFactory<Listing, String>("isCompetitive"));
private boolean isCompetitive = true;
. . .
public void setIsCompetitive(boolean isCompetitive){
    this.isCompetitive = isCompetitive;
}
public boolean getIsCompetitive(){
    return this.isCompetitive; 
}
private BooleanProperty isCompetitive = new SimpleBooleanProperty(true);
public void setIsCompetitive(boolean isCompetitive){
    this.isCompetitive.set(isCompetitive);
}
public boolean getIsCompetitive(){
    return this.isCompetitive.get(); 
}
public BooleanProperty isCompetitiveProperty() {
    return isCompetitive;
}
@FXML
public TableView<Listing> allListings; 
...
for(int i = 0; i < AnotherClass.listings.size(); i++){
    allListingsData.add(new Listing(AnotherClass.listings.get(i))); 
}
...
return new Task<Void>() {
    @Override
    protected Void call() throws Exception {
         while(true){
              synchronized(AnotherClass.listings) {
                  for(int i = 0; i < AnotherClass.listings.size(); i++){
                      Response response = makeAPICall();
                      Platform.runLater(() -> {
                          allListings.getItems().get(i).setIsCompetitive(
                              response.isCompetitive()
                          );
                      }; 
                      Thread.sleep(1000);
                  }
              }
         }
    }
}