当前位置: 首页 > 知识库问答 >
问题:

CheckBoxTableCell不使用ObjectProperty

骆照
2023-03-14

扩展的SimpleObject属性

为了将这个通用实现用于布尔属性,我使用LazyLoadingObjectProperty

在我的表中,我想将布尔属性呈现为CheckBox

然而,CheckBoxTableCell似乎只适用于布尔属性,而不适用于对象属性

为什么会这样?我该如何解决?

这是一些代码:

public class ExampleTable extends Application {

    private static final int NUM_ELEMENTS = 5000;

    private final TableView<ExampleBean> table = new TableView<>();

    private final ObservableList<ExampleBean> data = FXCollections.observableArrayList();

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

    @Override
    public void start(final Stage stage) {
        final Scene scene = new Scene(new Group());
        stage.setTitle("Table View Sample");
        stage.setWidth(300);
        stage.setHeight(500);

        final TableColumn<ExampleBean, Boolean> c1 = new TableColumn<>("A");
        c1.setCellValueFactory(new PropertyValueFactory<ExampleBean, Boolean>("p1"));
        c1.setCellFactory(CheckBoxTableCell.forTableColumn(c1));
        c1.setEditable(true);
        c1.setPrefWidth(100);

        final TableColumn<ExampleBean, String> c2 = new TableColumn<>("B");
        c2.setCellValueFactory(new PropertyValueFactory<ExampleBean, String>("p2"));
        c2.setCellFactory(TextFieldTableCell.forTableColumn());
        c2.setEditable(true);
        c2.setPrefWidth(100);


        for (int i = 0; i < NUM_ELEMENTS; i++) {
            data.add(new ExampleBean());
        }

        final ScrollPane sp = new ScrollPane();
        sp.setContent(table);
        sp.setMaxHeight(Double.POSITIVE_INFINITY);
        sp.setMaxWidth(Double.POSITIVE_INFINITY);
        sp.setFitToHeight(true);
        sp.setFitToWidth(true);

        table.setEditable(true);
        table.setItems(data);
        // table.setMaxHeight(Double.POSITIVE_INFINITY);
        // table.setMaxWidth(Double.POSITIVE_INFINITY);
        table.getColumns().addAll(c1, c2);

        final ContextMenu cm = new ContextMenu();
        cm.getItems().add(new MenuItem("bu"));
        table.setContextMenu(cm);

        final VBox vbox = new VBox();
        vbox.setSpacing(5);
        VBox.setVgrow(sp, Priority.ALWAYS);
        vbox.getChildren().addAll(sp);

        scene.setRoot(vbox);

        stage.setScene(scene);
        stage.show();
    }
}

public class ExampleBean {

    private ObjectProperty<Boolean> p1;

    private ObjectProperty<String> p2;


    public ExampleBean() {
        p1 = new SimpleObjectProperty(true);
        p1.addListener((o, ov, nv) -> {
            System.err.println("Value changed " + ov + " -> " + nv);
        });

        p2 = new SimpleObjectProperty(Integer.toString(new Random().nextInt()));
        p2.addListener((o, ov, nv) -> {
            System.err.println("Value changed " + ov + " -> " + nv);
        });
    }

    public final ObjectProperty<Boolean> p1Property() {
        return this.p1;
    }

    public final ObjectProperty<String> p2Property() {
        return this.p2;
    }
}

请注意,该属性是使用Boolean初始化的。TRUE和CheckBoxCells未被选中。

此问题未使用/不需要:

public abstract class LazyLoadingObjectProperty<T> extends SimpleObjectProperty<T> {

    public LazyLoadingObjectProperty() {
        super();

    }

    public LazyLoadingObjectProperty(final Object bean, final String name, final T initialValue) {
        super(bean, name, initialValue);

    }

    public LazyLoadingObjectProperty(final Object bean, final String name) {
        super(bean, name);

    }

    public LazyLoadingObjectProperty(final T initialValue) {
        super(initialValue);

    }

    private boolean loaded = false;

    private final ChangeListener<T> valueChangeListener = (o, ov, nv) -> {
        valueExternallyUpdated(nv);
    };

    /**
     * Is called after the background task's finished (success or failure). Override
     * if needed. E.g. to bind the value afterwards.
     */
    protected void afterLoaded() {
        addListener(valueChangeListener);

    }

    /**
     * Returns a {@link Task} that will calculate this Property's value in the
     * background.
     *
     * @return a {@link Task} that will calculate this Property's value in the
     *         background.
     */
    protected abstract Task<T> createTask();

    protected T getFailedValue(final Throwable t) {
        return null;
    }

    @Override
    public T getValue() {
        if (!loaded) {
            startLoadingService();
        }
        return super.getValue();
    }

    public boolean isLoaded() {
        return loaded;
    }

    public void setLoaded(final boolean loaded) {



        // the loaded property has been reset manually. Remove change listener
        if (this.loaded && !loaded) {
            removeListener(valueChangeListener);
        }

        this.loaded = loaded;
    }

    @Override
    public void setValue(final T v) {
        super.setValue(v);
    }

    /**
     * Starts the {@link Task} that will calculate this Property's value in the
     * background.
     */
    protected void startLoadingService() {
        setLoaded(true);
        final Task<T> s = LazyLoadingObjectProperty.this.createTask();

        LazyLoadingThreads.getExecutorService().submit(s);

        s.setOnFailed(e -> {
            setValue(getFailedValue(e.getSource().getException()));
            afterLoaded();
        });

        s.setOnSucceeded(e -> {
            setValue(s.getValue());
            afterLoaded();
        });

    }

    /**
     * Override this callback method to handle external value-change-events
     * (not-lazily-loaded). This callback is only called, if the value is updated
     * manually, i.e., not via the lazy-loading mechanism.
     *
     * @param nv
     *            the new value
     */
    protected void valueExternallyUpdated(final T nv) {
        // override if needed

    }

}

在这里也可以找到mwe。


共有1个答案

宫瀚
2023-03-14

这肯定是一个缺陷,至少在文档中是这样,但在实现中也是这样:选中的复选框和索引处的observeValue之间的自动bidi绑定(如果可能的话)是设计意图。即使在可能的情况下,实现也无法满足该要求。

快速破解是修复错误的自定义子类,类似(未经正式测试,小心!):

public static class FixedCheckBoxTableCell<S, T> extends CheckBoxTableCell<S, T> {

    @Override
    public void updateItem(T item, boolean empty) {
        checkCallback();
        super.updateItem(item, empty);
    }

    private void checkCallback() {
        if (getSelectedStateCallback() != null) return;
        ObservableValue<Boolean> observable = 
                (ObservableValue<Boolean>) getTableColumn().getCellObservableValue(getIndex());
        // handled by super
        if (observable instanceof BooleanProperty) return;
        // can't bidi-bind anyway
        if (!(observable instanceof Property)) return;
        // getting here if we have a ObjectProperty<Boolean>, that's not handled by super
        setSelectedStateCallback(index -> {
            ObjectProperty<Boolean> p = (ObjectProperty<Boolean>) getTableColumn().getCellObservableValue(index);
            return BooleanProperty.booleanProperty(p);
        });
    }


}
 类似资料:
  • 我想在我的模型中使用“reason”属性为添加一个工具提示。我该怎么做?

  • 问题内容: 我正在尝试向我的CheckBoxTableCells添加一个更改侦听器,但它似乎无法正常工作。我以CheckBoxes为例,说明它们的工作方式相同。但是,当我更改其值时没有输出。如何将一个正确地添加到checkboxtablecell? 当前代码: 问题答案: 的是从继承,它只是指示是否在UI部件中选择。由于您可能没有启用单元格选择,因此该单元格永远不会被选中。无论如何,这都不是您要找

  • 我有一个TableView,其中的一列应该是布尔值的复选框(javafx16,java11),但出于某种原因,复选框拒绝实际绑定到对象的字段。尝试使用专门为布尔列设计的forTableColumn静态方法已经失败了,我尝试扩展CheckBoxTableColumn并在其内部进行绑定,但没有任何效果(尽管我不需要仅为基本绑定这样做)。 在FXML的控制器中,我正在调用

  • 问题内容: 此页面- http://labs.qt.nokia.com/2011/10/28/rpath-and- runpath/ -说,大约为了在ld.so库搜索: 然后建议: 运送二进制文件时,请使用RPATH而不是RUNPATH或确保在运行它们之前已设置LD_LIBRARY_PATH。 那么,with的使用是不好的,因为kind- of会取消,因此间接动态加载无法按预期工作?但是,为什么然

  • 正是标题所说的。有没有办法在不安装TCL的情况下使用matplotlib库?请不要告诉我咬紧牙关安装TCL——我知道怎么做,但出于我自己(好吧,也许很愚蠢)的原因,我不想这么做。 我不关心显示的图,我只希望能够输出他们在png。我尝试了各种各样的东西(使用不同的后端等),但是matplotlib总是想找到tcl来工作:(为什么TCL对matplotlib如此重要? 此外,请注意,我正在使用wind

  • 当登录失败时,我试图重定向登录页面上输入的用户名,但在我的控制器中,从“@modelattribute(”user“)”检索的用户的用户名为空。当我不使用spring security时,这是有效的。 我假设form实际上首先发送到spring security,然后重定向到控制器,因此在spring security之间输入的信息丢失。 编辑(解决方案): 谢谢。@James创建一个failur