7

I'm trying to find different ways of selecting multiple items in a ListView. The GUI will be running on a touch screen monitor, So I won't be able to CTRL+Click. From researching through various past posts, I have been able to implement Multiple Selection via keeping all the selected items in an Array and then looping through it to get the final selections. The only problem I have with my code is that compared to a CTRL +click , the selection is done smoothly, where as my code leads to a type flickering every time a new item is selected. So basically the listView clears all the selections and then selects the correct ones. Is there a way to make this transition go smoothly? Would it be easier to mimic a touch to have CTRL+click effect?

selectedList = new int[totalTypes];//total number of item properties

for(int x=0; x<selectedList.length;x++){//0 = not selected, 1 = selected
    selectedList[x]=0;
}
testView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);

    testView.setOnMouseClicked(new EventHandler<Event>(){
        @Override
        public void handle(Event event){
                if(selectedList[testView.getSelectionModel().getSelectedIndex()]==0){
                    selectedList[testView.getSelectionModel().getSelectedIndex()]=1;
                }
                else{
                    selectedList[testView.getSelectionModel().getSelectedIndex()]=0;
                }

                for(int x=0; x<selectedList.length;x++){
                    if(selectedList[x]==1){
                        testView.getSelectionModel().select(x); 
                    }
                    else{
                        testView.getSelectionModel().clearSelection(x);;
                    }
                }


        }

    });
Ammar
  • 71
  • 4
  • seem you want to run it on a touch-enabled devices, you should use `setOnTouchPressed` instead `setOnMouseClicked` – TomN Dec 01 '16 at 01:30
  • the flash should caused by `clear and reset` action, I don't think it's necessary for a correct design. – TomN Dec 01 '16 at 01:33

1 Answers1

9

You could handle changing the selection when a user clicks a ListCell yourself instead of using the standard event handling:

@Override
public void start(Stage primaryStage) {
    ListView<Integer> listView = new ListView<>();
    listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
    listView.getItems().setAll(1, 2, 3, 4, 5, 6, 7, 8, 9, 10);
    listView.addEventFilter(MouseEvent.MOUSE_PRESSED, evt -> {
        Node node = evt.getPickResult().getIntersectedNode();

        // go up from the target node until a list cell is found or it's clear
        // it was not a cell that was clicked
        while (node != null && node != listView && !(node instanceof ListCell)) {
            node = node.getParent();
        }

        // if is part of a cell or the cell,
        // handle event instead of using standard handling
        if (node instanceof ListCell) {
            // prevent further handling
            evt.consume();

            ListCell cell = (ListCell) node;
            ListView lv = cell.getListView();

            // focus the listview
            lv.requestFocus();

            if (!cell.isEmpty()) {
                // handle selection for non-empty cells
                int index = cell.getIndex();
                if (cell.isSelected()) {
                    lv.getSelectionModel().clearSelection(index);
                } else {
                    lv.getSelectionModel().select(index);
                }
            }
        }
    });

    Scene scene = new Scene(listView);

    primaryStage.setScene(scene);
    primaryStage.show();
}
fabian
  • 80,457
  • 12
  • 86
  • 114
  • This works flawlessly. Thank you! Out of curiosity, how does a node work here? I notice your assigning it to the cell. So does it act as the selected item per say?By the way I plan on using a touch screen monitor, So in my head i'm think the finger touch would be input as a mouse click? Or should I just change the event to a touch pressed? which then I cant get a node from. – Ammar Dec 02 '16 at 05:03
  • @Ammar: [`MouseEvent.isSynthesized`](https://docs.oracle.com/javase/8/javafx/api/javafx/scene/input/MouseEvent.html#isSynthesized--) seems to indicate that touch events will trigger mouse events. I didn't test this though. How the code in the answer works is by using the descendant `Node` of the `ListView` (which could e.g. be a `Text` node in a `ListCell`) to try to find a `ListCell` as parent. If this can be done, then further event handling is stopped and the information from that `ListCell` is used to modify the selection. Otherwise no cell was clicked and the event is handled as usual... – fabian Dec 02 '16 at 08:05
  • Oh I see, makes more sense now. I appreciate your help! – Ammar Dec 02 '16 at 08:14