首页 文章

JavaFX TableView中的遗留bean无法更新

提问于
浏览
1

我们将JavaFX集成到一个包含许多_____84694_ Java bean的大型遗留代码库中,即使用 java.beans.PropertyChangeSupport 实现的类型 .

JavaFX不支持更新这些样式的bean,只支持初始值,如javafx.scene.control.cell.PropertyValueFactory中所述

如果不存在与此模式匹配的方法,则会尝试调用get()或is()(即上例中的getFirstName()或isFirstName()) . 如果存在与此模式匹配的方法,则此方法返回的值将包装在ReadOnlyObjectWrapper中并返回到TableCell . 但是,在这种情况下,这意味着TableCell将无法观察ObservableValue的更改(如上面第一种方法中的情况) .

将bean升级到属性API不是一种选择,因为它们位于一个单独的代码库中,我们不希望添加JavaFX依赖项,因为旧的Java 6项目仍在使用它 .

我的问题是,如何在更改属性时更新TableView,而无需在表中的所有单个bean上添加/删除侦听器 .

我正在考虑创建我自己的PropertyValueFactory版本,它支持这个,但我想知道是否还有其他可能的解决方案 .

我已经制作了两个例子来说明这一点 .

使用老式bean的TableView

public class OldBeanTableView extends Application {
    public class OldBean {
        private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
        public static final String PROPERTY_NAME_FOO = "foo";
        private int foo = 99;

        public int getFoo() {
            return foo;
        }

        public void setFoo(int foo) {
            int oldValue = this.foo;
            this.foo = foo;
            pcs.firePropertyChange(PROPERTY_NAME_FOO, oldValue, foo);
        }

        public void addPropertyChangeListener(PropertyChangeListener listener) {
            pcs.addPropertyChangeListener(listener);
        }

        public void removePropertyChangeListener(PropertyChangeListener listener) {
            pcs.removePropertyChangeListener(listener);
        }
    }

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        ObservableList<OldBean> beans = FXCollections.observableArrayList();
        beans.add(new OldBean());

        TableView<OldBean> tableView = new TableView<>();
        TableColumn<OldBean, Integer> column = new TableColumn<OldBeanTableView.OldBean, Integer>();
        tableView.getColumns().add(column);
        column.setCellValueFactory(new PropertyValueFactory<>("foo"));

        tableView.setItems(beans);
        primaryStage.setScene(new Scene(tableView));
        primaryStage.show();
        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(() -> beans.get(0).setFoo(beans.get(0).getFoo() + 1), 0,
                1, TimeUnit.SECONDS);
    }

}

使用新bean的TableView

public class NewBeanTableView extends Application {

    public class NewBean {
        private IntegerProperty fooProperty = new SimpleIntegerProperty(0);

        public int getFoo() {
            return fooProperty.get();
        }

        public void setFoo(int foo) {
            fooProperty.set(foo);
        }

        public IntegerProperty fooProperty() {
            return fooProperty;
        }
    }

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {

        ObservableList<NewBean> beans = FXCollections.observableArrayList();
        beans.add(new NewBean());

        TableView<NewBean> tableView = new TableView<>();
        TableColumn<NewBean, Integer> column = new TableColumn<NewBeanTableView.NewBean, Integer>();
        tableView.getColumns().add(column);
        column.setCellValueFactory(new PropertyValueFactory<>("foo"));

        tableView.setItems(beans);
        primaryStage.setScene(new Scene(tableView));
        primaryStage.show();
        Executors.newScheduledThreadPool(1).scheduleAtFixedRate(() -> beans.get(0).setFoo(beans.get(0).getFoo() + 1), 0,
                1, TimeUnit.SECONDS);
    }

}

2 回答

  • 2

    使用JavaBeanProperty作为valueFactory的一个非常快速的示例:

    Callback<CellDataFeatures<OldBean, Integer>, ObservableValue<Integer>> valueFactory = cdf -> {
        OldBean bean = cdf.getValue();
        JavaBeanObjectProperty<Integer> wrappee;
        try {
            wrappee = JavaBeanObjectPropertyBuilder.create()
                    .name("foo").bean(bean).build();
    
            return wrappee;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    };
    column.setCellValueFactory(valueFactory);
    

    请注意,bean必须有方法add / removePropertyChangeListeners(无论如何你的真正的bean都会:-)才能工作 .

  • 2

    推断kleopatra对通用解决方案的回答 .

    public class LegacyValueFactory<T, F> implements Callback<CellDataFeatures<T, F>, ObservableValue<F>> {
        private String propertyName;
        public LegacyValueFactory(String propertyName) {
            this.propertyName = propertyName;
        }
        @Override
        public ObservableValue<F> call(CellDataFeatures<T, F> param) {
            try {
                return JavaBeanObjectPropertyBuilder.create().name(propertyName).bean(param.getValue()).build();
            } catch (NoSuchMethodException e) {
                e.printStackTrace();
            }
            return null;
        }
    }
    

    用法

    column.setCellValueFactory(new LegacyValueFactory<OldBean, Integer>("foo"));
    

相关问题