JavaFX ListView selectedItemProperty 未在clearSelection(index) 上触发

标签 java listview user-interface javafx multipleselection

我正在使用 JavaFX 作为我正在编写的应用程序的 GUI。我的 GUI 中有一个 ListView 和一个按钮。

我希望 ListView 在鼠标单击时保持多重选择,并且仅在再次单击时删除选择(这有效)。

我还需要验证是否已在 ListView 中选择了某些内容,如果未启用任何内容,则禁用该按钮(适用于选择,但不适用于取消选择)。

这是我的按钮启用和禁用代码(这不起作用):

//Binding used to enable and disable the button
    BooleanBinding validEntriesBinding = new BooleanBinding(){
        {
            super.bind(listView.getSelectionModel().selectedItemProperty());
        }
        @Override
        protected boolean computeValue() {
            log.info("No individual item selected? " + 
                    (listView.getSelectionModel().getSelectedItems().isEmpty()));
            log.info("Selected items: " + listView.getSelectionModel().getSelectedItems().toString());
            return (listView.getSelectionModel().getSelectedItems().isEmpty());
        }
    };

    button.disableProperty().bind(validEntriesBinding);

这是我用于捕获鼠标选择的代码(这是有效的,解决方案是从 fabian 的 this SO 答案开发的):

//Example sourced from stackoverflow.com/questions/40900478/mimicking-ctrlclick-multiple-selection-in-listview-using-javafx
        //Answer by fabian
        //Must use MouseEvent.MOUSE_PRESSED and not MOUSE_CLICKED, otherwise the selection does not work
        listView.addEventFilter(MouseEvent.MOUSE_PRESSED, event -> {
            Node node = event.getPickResult().getIntersectedNode();

            while(node != null && node != listView && !(node instanceof ListCell)){
                node = node.getParent();
            }

            if(node instanceof ListCell){
                event.consume();
                listView.requestFocus();

                ListCell cell = (ListCell) node;
                if(!cell.isEmpty()){
                    if(cell.isSelected()){
                        log.info("Clear selection...");
                          listView.getSelectionModel().clearSelection(cell.getIndex());
                              log.info("Selection cleared");
                    }
                    else{
                          log.info("Selecting...");
                        listView.getSelectionModel().select(cell.getIndex());
                        log.info("Selected");
                    }
                }
                else{
                    log.warn("Cell is empty... cannot select");
                }
            }
            else{
                log.warn("Unable to handle event for " + node.getId() + " " + node.getClass());
            }
        });

这是我运行应用程序时的输出:

    //Before click, button disabled
    No individual item selected? true
    Selected items: []

    //First click selecting a cell, button enabled
    Selecting...
    No individual item selected? false
    Selected items: [SV124]
    Selected

    //Second click deselecting the first selected cell, button stays
    //enabled as the BooleanBinding never fires
    Clear selection...
    Selection cleared

为什么 BooleanBinding 不会在 listView.getSelectionModel().clearSelection(cell.getIndex()); 上触发?或者,更直接地说,为什么当选择为空时 listView.getSelectionModel().selectedItemProperty() 不会触发?根据 Javadoc 它应该在空时返回 null,所以不应该捕获它吗?

最佳答案

从 ListView 的选择模型中删除选定的索引似乎无法使selectedItemProperty()失效。 (这似乎是一个错误。)

如果您绑定(bind)到 selectedIndexProperty 而不是 selectedItemProperty,它就会起作用:

BooleanBinding validEntriesBinding = new BooleanBinding(){
    {
        super.bind(listView.getSelectionModel().selectedIndexProperty());
    }
    @Override
    protected boolean computeValue() {
        log.info("No individual item selected? " + 
                (listView.getSelectionModel().getSelectedItems().isEmpty()));
        log.info("Selected items: " + listView.getSelectionModel().getSelectedItems().toString());
        return (listView.getSelectionModel().getSelectedItems().isEmpty());
    }
};

也许,由于您启用了多项选择,所以最好还是绑定(bind)到所选项目的列表:

BooleanBinding validEntriesBinding = new BooleanBinding(){
    {
        super.bind(listView.getSelectionModel().getSelectedItems());
    }
    @Override
    protected boolean computeValue() {
        log.info("No individual item selected? " + 
                (listView.getSelectionModel().getSelectedItems().isEmpty()));
        log.info("Selected items: " + listView.getSelectionModel().getSelectedItems().toString());
        return (listView.getSelectionModel().getSelectedItems().isEmpty());
    }
};

请注意,如果将 validEntriesBinding 设置为局部变量,则很容易出现 accidental garbage collection 。您应该将其设为一个字段:

private BooleanBinding validEntriesBinding ;

// ...

validEntriesBinding = new BooleanBinding(){
    {
        super.bind(listView.getSelectionModel().getSelectedItems());
    }
    @Override
    protected boolean computeValue() {
        log.info("No individual item selected? " + 
                (listView.getSelectionModel().getSelectedItems().isEmpty()));
        log.info("Selected items: " + listView.getSelectionModel().getSelectedItems().toString());
        return (listView.getSelectionModel().getSelectedItems().isEmpty());
    }
};

关于JavaFX ListView selectedItemProperty 未在clearSelection(index) 上触发,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44786038/

相关文章:

java - 接口(interface)中的方法数

ios - UIVibrancyEffect UIVisualEffectView subview 不够生动

java - 使命令行驱动的回合制角色扮演游戏适应 swing 的事件驱动范例

java - 如何将多个 foreach 压缩为一个 for-each ?

java - JPL/SWI Prolog 不工作

java - 使用 spring boot 应用程序属性设置 tomcat 属性

qt - QML ListView、SwipeView 等 - 避免与其他 UI 组件重叠

android - 为什么设置 setBackgroundColor 在我的自定义 listView 中不起作用

android - 如何调用 ListView 中的按钮单击?

python - 如何从.cpp调用.py GUI?