JavaFX - 从任务更新表行

时间:2017-03-30 15:21:04

标签: java javafx

我正在尝试从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 TestController implements Initializable {

UpdateTableTask updateTableTask = new UpdateTableTask(); 

@FXML
public TableView<Listing> allListings; 
@FXML
public TableColumn<Listing, String> nameCol;
public TableColumn<Listing, String> idCol;
public TableColumn<Listing, String> skuCol;
@FXML
public final ObservableList<Listing> allListingsData = FXCollections.observableArrayList();

public void initialize(URL url, ResourceBundle rb) {



    for(int i = 0; i < AnotherClass.listings.size(); i++){

        allListingsData.add(AnotherClass.listings.get(i)); 
    }
    nameCol.setCellValueFactory(new PropertyValueFactory<Listing, String>("name"));
    idCol.setCellValueFactory(new PropertyValueFactory<Listing, String>("id"));
    skuCol.setCellValueFactory(new PropertyValueFactory<Listing, String>("SKU"));
    allListings.setItems(allListingsData);

    updateTableTask.launch();

}   



}

我的列表类:

public class Listing {
private String name;
private String id;
private String sku;
private double maxPrice;
private double minPrice;
private double currentPrice;
private int quantity; 
private boolean isFBA; 
private boolean active;
private boolean needsUpdate = false;
private double newPrice;
private double shipping;
private boolean isCompetitive = true;
private String buyBoxName = "unknown"; 
//private String productId;
private String asin;
public Listing(String name, String id, String sku, double minPrice, double maxPrice, double currentPrice, int quantity, String asin, boolean isFBA, boolean active, double shipping){
    this.name = name;
    this.id = id; 
    this.sku = sku;
    this.maxPrice = maxPrice;
    this.minPrice = minPrice; 
    this.currentPrice = currentPrice;
    this.quantity = quantity;        
    this.isFBA = isFBA; 
    this.active = active;
    this.shipping = shipping;
    //this.productId = productId;
    this.asin = asin;
  }
  public String getShippingLabel(){
     String result;
      if(Double.compare(this.shipping, 0.0) == 0){
            result = "Standard Free Shipping";
       }else{
            result = "Default Amazon Template"; 
       }
       return result;
   }
   public String getASIN(){
        return this.asin; 
   }
    public String getName(){
       return this.name;
    }

    public String getId(){
        return this.id;
    }

    public int getQuantity(){
       return this.quantity;  
    }
    public boolean getNeedsUpdate(){
        return this.needsUpdate;
    }


    public void setNeedsUpdate(boolean b){
        this.needsUpdate = b; 
    }

    public void setNewPrice(double price){
        this.newPrice = price;
    }

    public double getNewPrice(){
        return this.newPrice; 
    }

    public String getSKU(){
        return this.sku; 
    }

    public double getCurrentPrice(){
        return this.currentPrice;
    }

   public void setCurrentPrice(double price){
        this.currentPrice = price; 
    }

    public boolean getIsFBA(){
       return this.isFBA;
   }

    public void setIsFBA(boolean isFBA){
        this.isFBA = isFBA;
    }

    public double getMinPrice(){
        return this.minPrice; 
    }

    public double getMaxPrice(){
        return this.maxPrice;
    }

    public double getShipping(){
        return this.shipping; 
    }

    public void setIsCompetitive(boolean isCompetitive){
        this.isCompetitive = isCompetitive;
    }

    public boolean getIsCompetitive(){
        return this.isCompetitive; 
    }

    public void setNewPriceToMin(){
        this.newPrice = this.minPrice; 
    }

    public void setNewPriceToMax(){
        this.newPrice = this.maxPrice; 
    }

    public void setBuyBoxName(String name){
        this.buyBoxName = name; 
    }

    public String getBuyBoxName(){
        return this.buyBoxName; 
    }
}

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

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);
                          }

                       }
                  }

            }
        }
    }
}

(手动输入代码)

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

1 个答案:

答案 0 :(得分:0)

它有点难,因为你提供的代码有点不完整而且实际上不会编译,所以我会修改一些东西然后做一些假设(这可能与你的实际用例不符) )。

我们假设你想要一个专栏:

@FXML
TableColumn<Listing, String> isCompetitiveCol;

你有一个propertyValueFactory:

isCompetitiveCol.setCellValueFactory(new PropertyValueFactory<Listing, String>("isCompetitive"));

更改您的Listing类以使用完整的JavaFX属性,而不仅仅是基本类型。例如,而不是:

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;
}

这会将竞争属性转换为可监听的属性,可以在更新其值时触发更改和失效侦听器。每当属性发生更改时,PropertyValueFactory实现都将触发更新通知(以及后续更新表中单元格中的值)。

在使用线程时,您需要确保不要更新JavaFX应用程序线程的isCompetitive属性值(作为从属性更新触发的场景图的更新)只能出现在JavaFX应用程序线程上)。您可以使用Platform.runLater()运行任何更新来完成此操作。

所以你的任务可以是这样的:

@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);
                  }
              }
         }
    }
}

注意,我将TableView项目中的列表对象与AnotherClass.listings类中的列表对象分开(通过使用allListingsData.add(new Listing(AnotherClass.listings.get(i)));创建列表)。这是为了确保如果您有其他线程更新AnotherClass.listings值,那么通过PropertyValueFactory建立的链接尝试更新您的表并不会产生副作用。而是在platform.runLater调用中将更新从AnotherClass.listings传输到TableView,以确保只在需要更改表时才更改表。

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

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