JavaFX TableView中的遗留bean未更新

时间:2015-08-28 12:13:11

标签: java javafx javafx-8

我们正在将JavaFX集成到包含许多“原始”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版本,它支持这个,但我想知道是否还有其他可能的解决方案。

我已经举了两个例子来说明这一点。

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 个答案:

答案 0 :(得分: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都会:-)才能工作。

答案 1 :(得分: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"));