简体   繁体   English

Javafx更新对象属性上的ListCell

[英]Javafx update ListCell on object property

I'm trying to update the style class of a List Cell depending on a field that can be edited in another panel. 我试图根据可以在另一个面板中编辑的字段来更新列表单元格的样式类。

I tried the following but after editing the filed it changes the style but as well it changes the style of other ListCells on the list. 我尝试了以下操作,但是在编辑文件后,它会更改样式,但同时也会更改列表中其他ListCell的样式。

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

There are two issues with your code that I can see: 我的代码有两个问题,我可以看到:

First, the styleClass is represented by a List , which can of course hold duplicate entries. 首先, styleClassList表示,它当然可以保存重复的条目。 So if you are unlucky enough that the cell is reused from one item with a warning to another item with a warning, you will end up with the style class being added twice. 因此,如果您很不幸地将单元格从一个带有警告的项目重用到另一个带有警告的项目,您将最终将样式类添加两次。 The remove(...) method then only removes one copy, so as you scroll through your list you will start to see inconsistent behavior. 然后, remove(...)方法仅删除一个副本,因此,当您滚动浏览列表时,将开始看到不一致的行为。

If you are stuck with JavaFX 2.2, you need to do the following: 如果您坚持使用JavaFX 2.2,则需要执行以下操作:

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

If you really want to bullet-proof it, the way to ensure you remove all occurrences is to use the following in place of your call to remove(...) : 如果您真的想对其进行防弹,请确保使用以下方法代替调用remove(...)的方法来确保消除所有情况:

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

If you can use JavaFX 8 (ie Java 8) you should probably consider using a `PseudoClass' instead, which is much easier, and allegedly more efficient. 如果您可以使用JavaFX 8(即Java 8),则可能应该考虑使用“ PseudoClass” ,它更简单,而且据说效率更高。 (Plus, using lambdas in place of all those anonymous inner classes will make your code much more manageable.) (此外,使用lambda代替所有这些匿名内部类将使您的代码更易于管理。)

Second, whenever the cell is updated, you register a listener with the appropriate property on the item. 其次,每当更新单元格时,就在项目上注册具有适当属性的侦听器。 So when the cell is reused to represent a new item (for example, as the user scrolls through the list), it will be listening to properties from multiple items. 因此,当单元格被重用来表示一个新项目时(例如,当用户滚动列表时),它将监听多个项目的属性。 You need to arrange to remove the listener as needed. 您需要根据需要安排删除监听器。

I prefer to approach this by creating a default ListCell and observing its itemProperty() , as this gives you clean access to the old item as well as the new one when it changes. 我更喜欢通过创建默认的ListCell并观察其itemProperty()来实现此目的,因为这使您可以对旧项目以及更改后的新项目进行干净的访问。 So you can do something like this: 因此,您可以执行以下操作:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM