2014-10-29 43 views
1

此問題進一步發生在JavaFX: Disable multiple rows in TableView based on other TableView停止。我想產生一個更普遍的話題,其他人也可以從中受益。JavaFX:BooleanBindings綁定多個EasyBind地圖

我也有兩個tableviews。當table1包含相同的對象時,我也想禁用table2中的一行。這是通過下面的代碼實現:

//Check if a row needs to be disabled: this is achieved with a rowfactory 
ObservableList<String> listOfSKUs = EasyBind.map(table1.getItems(),Product::getSKU); 
table2.setRowFactory(tv -> { 

    TableRow<Product> row = new TableRow<>(); 

    //The row doesnt need to be checked when it is empty, thats the first part 
    //The second part is a big OR: the row is a gift card OR the listOfSkus contains the row. In this last one, the amount also needs to be checked. 

    row.disableProperty().bind(Bindings.createBooleanBinding(() -> 
     row.getItem() != null && 
     (row.getItem().getProductName().equals("Kadobon") || 
     (listOfSKUs.contains(row.getItem().getSKU()) //&& some part to check for the amount) 
     ), listOfSKUs, row.itemProperty())); 

    return row; 

}); 

現在我只想禁用行時:

  1. 從表1的產品的SKU也是在表2(這個工程現在)
  2. 表2中的產品的量爲負

我不知道如何檢查的數額,因爲我需要與該特定SKU相關的量。如何在一個BooleanBinding中創建多個貼圖?

任何幫助,非常感謝!

+0

你可能需要詳細說明你在這裏的類型。它看起來像'table1'和'table2'都是'TableView 's。因此,表1中的產品數量必須與表2中具有相同SKU的產品數量相同(它們不是相同的對象..)? – 2014-10-29 14:54:00

+0

@James_D沒有不同的對象,它們只有相同的SKU。問題是這樣的:表2中的產品需要放在table1中,並且金額爲負值。我知道如何做到這一點。但是,table1中可能有一個具有相同SKU的對象,其積極金額不是來自table2,而是來自其他來源。通過上面的解決方案,該行在禁用時不會被禁用,因爲表1中的數量是正數而不是負數。你到底懂不懂呢? – bashoogzaad 2014-10-29 15:02:25

回答

1

這聽起來對您而言,您可能會從重新考慮您的對象模型中受益。看起來您的Product有兩個不同的值,您可以參考amount:一個顯示在表1中,另一個顯示在表2中。如果您製作Product類的這兩個不同字段,那麼所有這些變得容易得多,因爲您可以使用相同的實際對象(僅在列中顯示不同的屬性)來表示這兩個表中的項目。然後禁用行的標準就成爲您正在查看的對象的函數(以及table2.getItems().contains(...))。

另一種選擇可能是一個SKU類:

public class SKU { 

    private final StringProperty sku = ... ; 

    // Obviously use more meaningful names for these: 
    private final ObjectProperty<Product> table1Product = ... ; 
    private final ObjectProperty<Product> table2Product = ... ; 

    // getters, setters etc... 

} 

然後這兩個表可以TableView<SKU> s的上只是看着從正確的產品性能列單元格的值工廠。在table1的行工廠中,row.getItem()返回SKU對象,並且可以根據需要查看table2屬性。

如果你真的不能這樣做,那麼一種方法是維護一個ObservableMap<String, Double>,它將SKU映射到表2中顯示的數量。這是一些工作,但不是太糟糕了:

ObservableMap<String, Double> skuAmountLookup = table2.getItems().stream().collect(
    Collectors.toMap(Product::getSKU, Product::getAmount, 
    // the next argument is a merge function, which is used if there are two (or more) items 
    // in table2 with the same SKU. This function would replace the first value by the second. 
    // If the SKUs are unique it doesn't really matter what you have here... 
    (x, y) -> y, 
    () -> FXCollections.observableHashMap())); 

現在你需要不斷更新地圖時該表內容的變化:

table2.getItems().addListener((ListChangeListener.Change<? extends Product> change) -> { 
    // can just do skuAmountLookup.clear(); followed by skuAmountLookup.putAll(...) 
    // passing in the same data used above to initialize it 
    // That's pretty inefficient though, the following will just update what's needed. 
    // This assumes SKUs are unique in table 2: 
    while (change.next()) { 
     if (change.wasAdded()) { 
      change.getAddedSubList().forEach(product -> 
       skuAmountLookup.put(product.getSKU(), product.getAmount())); 
     } 
     if (change.wasRemoved()) { 
      change.getRemoved().forEach(product -> skuAmountLookup.remove(product.getSKU())); 
     } 
    } 
}); 

然後禁用標準可以是這樣的

row.disableProperty().bind(Bindings.createBooleanBinding(
    () -> row.getItem() != null && 
      skuAmountLookup.containsKey(row.getItem().getSKU()) && 
      skuAmountLookup.get(row.getItem().getSKU()) < 0, 
    skuAmountLookup, 
    row.itemProperty())); 

我還沒有嘗試過這些,但它應該工作。這裏有兩個假設:

  1. 的SKU表2是不會改變在表2
  2. 量獨特的,比其他項目添加或從表中刪除。如果需要,這可以被解決,但是它爲table2的項目上的聽衆增加了一層複雜性。
+0

你能解釋一下你的意思嗎?你的答案似乎不完整。 – bashoogzaad 2014-10-29 15:45:28

+0

對不起,不小心點擊「發佈」過早。 – 2014-10-29 15:46:37

+0

感謝您的回答!當我嘗試創建ObservableMap時,出現錯誤:找不到適合toMap的方法。這可能是什麼? – bashoogzaad 2014-10-29 16:31:36