2014-10-31 196 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