Javafx 更新对象属性上的 ListCell

标签 java listview javafx

我正在尝试根据可以在另一个面板中编辑的字段来更新列表单元格的样式类。

我尝试了以下操作,但在编辑文件后,它更改了样式,但也更改了列表中其他 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;
        }
});

最佳答案

我发现您的代码存在两个问题:

首先,styleClass 由一个List 表示,它当然可以保存重复的条目。因此,如果您很不幸,该单元格从一个带有警告的项目重用到另一个带有警告的项目,则最终会导致样式类被添加两次。然后,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 ;
         }
});

关于Javafx 更新对象属性上的 ListCell,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26677697/

相关文章:

java - 使用 CardLayout 将自定义面板添加到 Applet

java - Android 如何从 Parse 列表中删除选定的项目

android - 在 ListView 中滚动时切换按钮更改状态

java - 检索firebase实时数据库中节点下的所有数据

Java GUI - 添加文本字段

java - java中的静态同步方法有什么用?

c# - 带有 AllowColumnReorder 的 ListView OwnerDraw 不能正常工作

hibernate - javaFX FXML,使用 Hibernate 填充 TableView

JavaFX 8 - 自定义控件及其子控件

java - 在 JavaFX 应用程序的 SQLite 中插入数据