JavaFx:ListView CheckBoxListCell 选择

标签 java listview javafx javafx-8

我在使用 CheckBoxListCell 时遇到 ListView 问题。当我选中/取消选中某个项目时,该项目不会被选择/聚焦,这是预期的,因为复选框也是该项目的一部分,而不仅仅是文本部分。

这是一个简单的代码,您可以验证它。

import javafx.beans.property.BooleanProperty;
import javafx.beans.property.SimpleBooleanProperty;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.CheckBox;
import javafx.scene.control.ListView;
import javafx.scene.control.cell.CheckBoxListCell;
import lombok.Getter;

import java.net.URL;
import java.util.ResourceBundle;

public class Controller implements Initializable {
    @FXML private ListView<Model> listView;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
//      without selection
//      listView.setCellFactory(CheckBoxListCell.forListView(Model::getSelected));

        // actual "bad" solution
        listView.setCellFactory(factory -> {
            CheckBoxListCell<Model> cell = new CheckBoxListCell<Model>() {
                @Override
                public void updateItem(Model item, boolean empty) {
                    super.updateItem(item, empty);
                    if (empty) {
                        setText(null);
                        setGraphic(null);
                        return;
                    }
                    ((CheckBox) getGraphic()).selectedProperty().addListener(
                            (observable, oldValue, newValue) -> listView.getSelectionModel().select(getItem()));
                }
            };
            cell.setSelectedStateCallback(Model::getSelected);
            return cell;
        });

        ObservableList<Model> items = FXCollections.observableArrayList();

        items.add(new Model("A", true));
        items.add(new Model("B", true));
        items.add(new Model("C", false));

        listView.setItems(items);
    }

    @Getter
    private class Model {
        String text;
        BooleanProperty selected;

        private Model(String text, Boolean selected) {
            this.text = text;
            this.selected = new SimpleBooleanProperty(selected);
        }

        @Override public String toString() {
            return text;
        }
    }
}

.fxml:

<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.control.ListView?>
<AnchorPane xmlns="http://javafx.com/javafx"
            xmlns:fx="http://javafx.com/fxml"
            fx:controller="list.Controller">
<ListView fx:id="listView"/>
</AnchorPane>

正如你所看到的,我找到了一个解决方案,或者更好地说是一个肮脏的解决方法,但我真的不喜欢它,因为它在每个 updateItem 上都会被调用,并且它会添加监听器n次这不太好。

任何其他想法/解决方案如何实现当我选中/取消选中组合框时整个项目被选择/聚焦。

最佳答案

这个答案只涵盖了问题的一部分:如何确保单元格图形属性上的监听器仅注册一次(如果我们无法控制何时设置图形)。

涉及的步骤:

  1. 定义一个安装“真实”监听器的 InvalidationListener(注意:必须是一个稍后能够删除的字段)
  2. 在实例化时在单元格的图形属性上注册监听器
  3. 实现“真实”方法的注册,以删除初始图形监听器以及安装所需的任何内容

代码片段(注意:监听选定的属性不是一个好主意,因为每当数据发生变化时它就会触发,而不仅仅是当用户单击复选框时!):

listView.setCellFactory(factory -> {
    CheckBoxListCell<Model> cell = new CheckBoxListCell<Model>() {
        // a listener on the graphicProperty: it installs the "real" listener
        InvalidationListener graphicListener = g -> {
            // installs the "real" listener on the graphic control once it is available 
            registerUIListener();
        };

        {
            // install the graphic listener at instantiation
            graphicProperty().addListener(graphicListener);
        }

        /** method to install a listener on a property of the graphic control
         * and unregisters the initially installed listener
         */
        private void registerUIListener() {
            if (!(getGraphic() instanceof CheckBox)) throw new IllegalStateException("checkBox expected");
            graphicProperty().removeListener(graphicListener);
            ((CheckBox) getGraphic()).selectedProperty().addListener(
                    (observable, oldValue, newValue) -> listView.getSelectionModel().select(getItem()));
        }
    };
    cell.setSelectedStateCallback(Model::selectedProperty);
    return cell;
});

关于JavaFx:ListView CheckBoxListCell 选择,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/56789144/

相关文章:

Javafx:jpeg 文件存在,但 Image 构造函数抛出 IllegalArgumentException!为什么?

JavaFX 动画/带 Pane 的 3d View

java - 如何获得 JavaFX 应用程序中的主要阶段?

java - Java打印函数输出说明

java - Jpinner setModel 不允许更改值

java - 分层存储常量的最佳实践

asp.net - 如何访问 ListView 中的按钮?特别是使用button_click来执行操作

java - 使用 selenium 在 java 中使用 testng 进行并行测试

android - 更改 ListView 中第一项的背景颜色

android - 最后一项点击空指针异常