JavaFX ListView - 通过鼠标单击添加项目到选择

JavaFX ListView - add items by mouseclick to selection

我只想通过鼠标(不按住 ctrl 或 shift)创建一个包含多个 selection 的 ListView

点击一个项目应该select这个项目。如果还有其他项目 selected,请将此新项目添加到 selected 列表。以前 select 编辑过此项时,将其删除。

我不知道要保留 selected 的项目。 selectionModel 上有一个名为 "selectIndices()" 的方法,它只接受一个或多个整数,而不是整数列表...

 DataTypesLV.getSelectionModel().selectedItemProperty().addListener(new ChangeListener <String>() {
        @Override
        public void changed(ObservableValue<? extends String> arg0, String oldVal, String newVal) {
            int idx = DataTypesLV.getItems().indexOf(newVal);
            if(newVal.equals(oldVal)){
                DataTypesLV.getSelectionModel().getSelectedIndices().remove(idx);
              } else {
                  DataTypesLV.getSelectionModel().getSelectedIndices().add(idx);
              }
        }
    });

大家有什么想法吗?

在 JavaFX 中更改控件的行为通常很困难。 "proper" 方法是创建一个新的皮肤实现,这涉及大量工作,并且由于行为 classes 目前不是 public API涉及很多"reinventing the wheel"。一个合理的 hack 是在鼠标事件被默认皮肤 class 接收之前拦截鼠标事件,并相应地修改选择。您可以使用事件过滤器执行此操作,使用事件来防止皮肤接收它:

import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.control.SelectionMode;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;

public class ListViewModifiedSelection extends Application {

    @Override
    public void start(Stage primaryStage) {
        ListView<String> listView = new ListView<>();
        listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);

        for (int i = 1 ; i <= 25 ; i++) {
            listView.getItems().add("Item "+i);
        }

        listView.setCellFactory(lv -> {
            ListCell<String> cell = new ListCell<String>() {
                @Override
                protected void updateItem(String item, boolean empty) {
                    super.updateItem(item, empty);
                    setText(empty ? null : item);
                }
            };

            cell.addEventFilter(MouseEvent.MOUSE_PRESSED, e -> {
                if (cell.isEmpty()) {
                    return ;
                }

                int index = cell.getIndex() ;
                if (listView.getSelectionModel().getSelectedIndices().contains(index)) {
                    listView.getSelectionModel().clearSelection(index);
                } else {
                    listView.getSelectionModel().select(index);
                }

                listView.requestFocus();

                e.consume();
            });

            return cell ;
        });

        primaryStage.setScene(new Scene(listView, 250, 450));
        primaryStage.show();
    }

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

阻止皮肤接收鼠标事件有点像 hack,这样做确实有破坏现有功能的风险。另一种更强大的解决方案可能是使用列表单元格中的复选框或类似的东西来管理您自己的 "selection" 功能。