2014-10-31 192 views
0

我想要更新列表單元格的樣式類,具體取決於可以在另一個面板中編輯的字段。Javafx更新對象屬性ListCell

我嘗試了以下,但在編輯該字段後,它改變了樣式,但它也改變了列表上其他ListCells的樣式。

private ListView<ProviderProduct> importProductsListView = //Set items in list 
importProductsListView.setCellFactory(
    new Callback<ListView<ProviderProduct>, ListCell<ProviderProduct>>() { 
     public ListCell<ProviderProduct> call(ListView<ProviderProduct> param) { 
      final ListCell<ProviderProduct> cell = new ListCell<ProviderProduct>(){ 

       public void updateItem(ProviderProduct providerProduct, boolean empty){ 
        super.updateItem(providerProduct, empty); 

         if(!empty) { 
          setText(providerProduct.toString()); 

          if(providerProduct.hasPriceWarning()){ 
           getStyleClass().add(Consts.CSS_ALERT); 
          }else{ 
           getStyleClass().remove(Consts.CSS_ALERT); 
          } 

          providerProduct.priceListinoProperty().addListener(
           new ChangeListener<BigDecimal>() { 
            @Override 
            public void changed(ObservableValue<? extends BigDecimal> observable,BigDecimal oldValue, BigDecimal newValue) { 

             if(providerProduct.hasPriceWarning()){ 
              if(!getStyleClass().contains(Consts.CSS_ALERT)){ 
               getStyleClass().add(Consts.CSS_ALERT); 
              } 
             }else{ 
              getStyleClass().removeAll(Collections.singleton(Consts.CSS_ALERT)); 
             } 
            } 
           }); 
         }else{ 
          setText(""); 
          getStyleClass().remove(Consts.CSS_ALERT); 
         } 
        } 
      }; 
      return cell; 
     } 
}); 

回答

1

有兩個問題與您的代碼,我可以看到:

首先,styleClassList,這當然可以容納重複的條目表示。所以如果你不幸運的話,那麼這個單元格會從一個具有警告的項目重用到另一個具有警告的項目,那麼你最終會添加兩次樣式類別。 remove(...)方法然後只刪除一個副本,所以當你滾動你的列表時,你會看到不一致的行爲。

如果你被卡住的JavaFX 2.2,你需要做到以下幾點:

if(providerProduct.hasPriceWarning() & ! getStyleClass().contains(Consts.CSS_ALERT){ 
    getStyleClass().add(Consts.CSS_ALERT); 
}else{ 
    getStyleClass().remove(Consts.CSS_ALERT); 
} 

如果你真的想防彈吧,這樣才能保證您刪除所有出現被使用在以下地方你的電話到remove(...)

getStyleClass().removeAll(Collections.singleton(CSS_ALERT)); 

如果你可以使用JavaFX的8(即Java的8)你可能應該考慮使用`PseudoClass'代替,這是容易得多,而且據說更有效。 (另外,使用lambda代替所有匿名內部類將使您的代碼變得更易於管理。)

其次,每當單元格更新時,都會在該項目上註冊一個具有相應屬性的偵聽器。因此,當單元格被重用來表示一個新項目時(例如,當用戶滾動列表時),它將會監聽來自多個項目的屬性。您需要根據需要安排刪除偵聽器。

我更喜歡通過創建默認ListCell並觀察它的itemProperty()來解決這個問題,因爲這可以讓您在舊項目以及新項目發生更改時能夠乾淨地訪問。所以你可以做這樣的事情:

importProductsListView.setCellFactory(
    new Callback<ListView<ProviderProduct>, ListCell<ProviderProduct>>() { 
     public ListCell<ProviderProduct> call(ListView<ProviderProduct> param) { 
      final ListCell<ProviderProduct> cell = new ListCell<ProviderProduct>(); 

      final ChangeListener<BigDecimal> priceListener = new ChangeListener<BigDecimal>() { 
       @Override 
       public void changed(ObservableValue<? extends BigDecimal> observable,BigDecimal oldValue, BigDecimal newValue) { 

        if(providerProduct.hasPriceWarning()){ 
         if(!getStyleClass().contains(Consts.CSS_ALERT)){ 
           getStyleClass().add(Consts.CSS_ALERT); 
         } 
        }else{ 
         getStyleClass().removeAll(Collections.singleton(Consts.CSS_ALERT)); 
        } 
       } 
      }); 

      cell.itemProperty().addListener(new ChangeListener<ProviderProduct>() { 
       @Override 
       public void changed(ObservableValue<? extends ProviderProduct> obs, ProviderProduct oldProduct, ProviderProduct newProduct) { 
        if (oldProduct != null) { 
         oldProduct.priceListinoProperty().removeListener(priceListener); 
        } 
        if (newProduct == null) { 
         cell.setText(null); 
         cell.getStyleClass().removeAll(Collections.singleton(Consts.CSS_ALERT); 
        } else { 
         cell.setText(newProduct.toString()); 
         if (newProduct.hasPriceWarning()) { 
          if (! cell.getStyleClass().contains(Consts.CSS_ALERT)) { 
           cell.getStyleClass().add(Consts.CSS_ALERT); 
          } 
         } else { 
          cell.getStyleClass().removeAll(Collections.singleton(Consts.CSS_ALERT)); 
         } 
         newProduct.priceListinoProperty().addListener(priceListener); 
        } 
       } 
      }); 

      return cell ; 
     } 
}); 
+0

偉大的反應和更好的方法來監聽單元格項目的變化,而不是直接向字段。我最後添加了'PseudoClass',我使用javafx 8來管理樣式的更新,它簡化並刪除了所有的條件。 – alexll 2014-11-02 13:01:10