JList - deselect when clicking an already selected item

后端 未结 6 1742
忘掉有多难
忘掉有多难 2020-12-10 04:36

If a selected index on a JList is clicked, I want it to de-select. In other words, clicking on the indices actually toggles their selection. Didn\'t look like this was suppo

相关标签:
6条回答
  • 2020-12-10 04:58

    Nick Dandoulakis' answer didn't quite work for me when selecting multiple items at once using a mouse click while pressing Shift.

    The following ListSelectionModel behaves as I'd expect it when selecting items using mouseclicks with Shift or Ctrl.

    Also, holding down Shift + Ctrl and pressing either or selects items the way I want it to.

    public static class ToggleableListSelectionModel extends DefaultListSelectionModel {
            private static final long serialVersionUID = 1L;
    
            @Override
            public void setSelectionInterval(int startIndex, int endIndex) {
                if (startIndex == endIndex) {
                    if (multipleItemsAreCurrentlySelected()) {
                        clearSelection();
                    }
                    if (isSelectedIndex(startIndex)) {
                        clearSelection();
                    }
                    else {
                        super.setSelectionInterval(startIndex, endIndex);
                    }
                }
                // User selected multiple items
                else {
                    super.setSelectionInterval(startIndex, endIndex);
                }
            }
    
            private boolean multipleItemsCurrentlyAreSelected() {
                return getMinSelectionIndex() != getMaxSelectionIndex();
            }
        }
    
    0 讨论(0)
  • 2020-12-10 04:59

    I know that this question already has an accepted answer, but I thought that I'd expand a bit, since I ended up stuck on this task for a few hours.

    I was trying to implement a click-to-deselect action for selected items, but my list implementation requires the use of Single-Selection mode, specified by

    JList jlist = new JList(new DefaultListModel());
    jlist.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    

    Unfortunately, this led to exceptions and redundant calls for many of the solutions for the click-to-deselect problem on many SO questions, including this answer by FuryComptuers above. Due to code in DefaultListSelectionModel.class, specifically in the addSelectionInterval(int index0, int index1) and removeSelectionInterval(int index0, int index1) methods, which calls back to the setSelectionInterval(int index0, int index1) method, caused a circular call that leads to (obviously) exceptions. This "problem" code can be seen below.

     // If we only allow a single selection, channel through
        // setSelectionInterval() to enforce the rule.
        if (getSelectionMode() == SINGLE_SELECTION) {
            setSelectionInterval(index0, index1);
            return;
        }
    

    Sawas Dalkitsis' answer solved this problem, but would still act weird when dragging the mouse on a selected item (the selected item will select and de-select itself over and over while dragging the mouse). This wouldn't seem like a problem, but (apparently) I have a shaky hand, and minor mouse movements while clicked resulted in unwanted behavior. I combined Sawas Dalkitsis answer and FuryComptuers's answer to get the following code, which seems to work as desired:

        JList jlist = new JList(new DefaultListModel());
        jList.setSelectionModel(new DefaultListSelectionModel() {
            private static final long serialVersionUID = 1L;
    
            boolean gestureStarted = false;
    
            @Override
            public void setSelectionInterval(int index0, int index1) {
                if(!gestureStarted){
                if (index0==index1) {
                    if (isSelectedIndex(index0)) {
                        removeSelectionInterval(index0, index0);
                        return;
                    }
                }
                super.setSelectionInterval(index0, index1);
                }
                gestureStarted = true;
            }
    
            @Override
            public void addSelectionInterval(int index0, int index1) {
                if (index0==index1) {
                    if (isSelectedIndex(index0)) {
                        removeSelectionInterval(index0, index0);
                        return;
                    }
                super.addSelectionInterval(index0, index1);
                }
            }
    
            @Override
            public void setValueIsAdjusting(boolean isAdjusting) {
                if (isAdjusting == false) {
                    gestureStarted = false;
                }
            }
    
        });
        jList.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
    

    Note: I didn't check this against the ListSelectionModel.SINGLE_INTERVAL_SELECTION, as Sawas Dalkitsis did, so use caution if implementing it in that case.

    0 讨论(0)
  • 2020-12-10 04:59

    You could always the ListSelectionListener instead of deciphering the point clicked and then translating it to the item selected.

    http://java.sun.com/docs/books/tutorial/uiswing/examples/events/index.html#ListSelectionDemo

    http://java.sun.com/docs/books/tutorial/uiswing/events/listselectionlistener.html

    http://java.sun.com/docs/books/tutorial/uiswing/examples/events/ListSelectionDemoProject/src/events/ListSelectionDemo.java

    In the above link for java file there is an implementation which can be easily improved to do "deselection" :)

    0 讨论(0)
  • 2020-12-10 05:07

    Looking at the Example "ListSelectionModel: Enabling Toggle Selection Mode" here: http://java.sun.com/products/jfc/tsc/tech_topics/jlist_1/jlist.html

    I have modified it slightly for multi-select list boxes (changed setSelectionInterval to addSelectionInterval) and eliminated a problem with re-selection if you click to de-select and move your mouse while the mouse is down (moved the gestureStarted check for both add and remove).

    objList.setSelectionModel(new DefaultListSelectionModel() {
        private static final long serialVersionUID = 1L;
    
        boolean gestureStarted = false;
    
        @Override
        public void setSelectionInterval(int index0, int index1) {
            if(!gestureStarted){
                if (isSelectedIndex(index0)) {
                    super.removeSelectionInterval(index0, index1);
                } else {
                    super.addSelectionInterval(index0, index1);
                }
            }
            gestureStarted = true;
        }
    
        @Override
        public void setValueIsAdjusting(boolean isAdjusting) {
            if (isAdjusting == false) {
                gestureStarted = false;
            }
        }
    
    });
    
    0 讨论(0)
  • 2020-12-10 05:09

    How about this?

    import javax.swing.DefaultListSelectionModel;
    import javax.swing.JFrame;
    import javax.swing.JList;
    import javax.swing.ListSelectionModel;
    
    public class A {
        public static void main(String[] args) {
            JFrame f = new JFrame("Test");
            final JList list = new JList(new String[] {"one","two","three","four"});
            list.setSelectionModel(new DefaultListSelectionModel(){
    
    
                @Override
                public void setSelectionInterval(int index0, int index1) {
                    if (index0==index1) {
                        if (isSelectedIndex(index0)) {
                            removeSelectionInterval(index0, index0);
                            return;
                        }
                    }
                    super.setSelectionInterval(index0, index1);
                }
    
                @Override
                public void addSelectionInterval(int index0, int index1) {
                    if (index0==index1) {
                        if (isSelectedIndex(index0)) {
                            removeSelectionInterval(index0, index0);
                            return;
                        }
                    super.addSelectionInterval(index0, index1);
                    }
                }
    
            });
            f.getContentPane().add(list);
            f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            f.pack();
            f.setVisible(true);
        }
    
    }
    

    It works but note one side effect... If you set the mode to multi selction like this for instance:

    list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION );
    

    you cannot select multiple objects via mouse drag. Ctrl (or shift) click works. I'm sure it can be fixed but i assume you asked this for single selection lists... If not modify your question and we can start thinking for solutions to the multiple selection problem.

    0 讨论(0)
  • 2020-12-10 05:10

    I extended FuryComptuers answer to support multiple selection, and fixed an issue where setSelectionInterval didn't work if it was called directly.

    public class ToggleableListSelectionModel extends DefaultListSelectionModel {
        private static final long serialVersionUID = 1L;
    
        private boolean mGestureStarted;
    
        @Override
        public void setSelectionInterval(int index0, int index1) {
            // Toggle only one element while the user is dragging the mouse
            if (!mGestureStarted) {
                if (isSelectedIndex(index0)) {
                    super.removeSelectionInterval(index0, index1);
                } else {
                    if (getSelectionMode() == SINGLE_SELECTION) {
                        super.setSelectionInterval(index0, index1);
                    } else {
                        super.addSelectionInterval(index0, index1);
                    }
                }
            }
    
            // Disable toggling till the adjusting is over, or keep it
            // enabled in case setSelectionInterval was called directly.
            mGestureStarted = getValueIsAdjusting();
        }
    
        @Override
        public void setValueIsAdjusting(boolean isAdjusting) {
            super.setValueIsAdjusting(isAdjusting);
    
            if (isAdjusting == false) {
                // Enable toggling
                mGestureStarted = false;
            }
        }   
    }
    
    0 讨论(0)
提交回复
热议问题