JList - 单击已选择的项目时取消选择

时间:2010-03-27 06:11:07

标签: java swing jlist

如果单击JList上的选定索引,我希望它取消选择。换句话说,点击索引实际上切换了他们的选择。看起来不支持,所以我尝试了

list.addMouseListener(new MouseAdapter()
{
   public void mousePressed(MouseEvent evt)
   {
      java.awt.Point point = evt.getPoint();
      int index = list.locationToIndex(point);
      if (list.isSelectedIndex(index))
         list.removeSelectionInterval(index, index);
   }
});

这里的问题是,在 JList已经对鼠标事件起作用之后,正在调用,因此它取消选择所有内容。然后我尝试删除所有JList的MouseListeners,添加我自己的,然后添加所有默认侦听器。这不起作用,因为在我取消选择后,JList会重新选择索引。无论如何,我最终想出的是

MouseListener[] mls = list.getMouseListeners();
for (MouseListener ml : mls)
   list.removeMouseListener(ml);
list.addMouseListener(new MouseAdapter()
{
   public void mousePressed(MouseEvent evt)
   {
      java.awt.Point point = evt.getPoint();
      final int index = list.locationToIndex(point);
      if (list.isSelectedIndex(index))
         SwingUtilities.invokeLater(new Runnable()
         {
            public void run()
            {
               list.removeSelectionInterval(index, index);
            }
         });
   }
});
for (MouseListener ml : mls)
   list.addMouseListener(ml);

......这很有效。但我不喜欢它。还有更好的方法吗?

6 个答案:

答案 0 :(得分:11)

在此处查看示例“ListSelectionModel:启用切换选择模式”: http://java.sun.com/products/jfc/tsc/tech_topics/jlist_1/jlist.html

我已经为多选列表框稍微修改了它(将setSelectionInterval更改为addSelectionInterval)并且如果在鼠标停止时单击取消选择并移动鼠标,则消除了重新选择的问题(移动了gestureStarted检查添加和删​​除)。

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;
        }
    }

});

答案 1 :(得分:4)

这个怎么样?

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);
    }

}

它有效但注意一个副作用......如果你将模式设置为多重选择,例如:

list.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION );

您无法通过鼠标拖动选择多个对象。 Ctrl(或shift)单击工作。我确定它可以修复,但我假设你问这个单选列表...如果不修改你的问题,我们就可以开始考虑多选问题的解决方案了。

答案 2 :(得分:3)

我知道这个问题已经有了一个公认的答案,但我认为我会扩大一点,因为我最终坚持这个任务几个小时。

我正在尝试为所选项目实施点击取消选择操作,但我的列表实现需要使用单一选择模式,由

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

不幸的是,这导致针对许多SO问题的点击取消选择问题的许多解决方案的例外和冗余调用,包括this answer上面的FuryComptuers。由于DefaultListSelectionModel.class中的代码,特别是addSelectionInterval(int index0, int index1)removeSelectionInterval(int index0, int index1)方法中的代码,这些方法回调setSelectionInterval(int index0, int index1)方法,导致循环调用导致(显然)异常。这个“问题”代码可以在下面看到。

 // 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解决了这个问题,但是当在所选项目上拖动鼠标时仍然会显得很奇怪(所选项目将在拖动鼠标时反复选择并取消选择) 。这似乎不是一个问题,但(显然)我有一个颤抖的手,点击时轻微的鼠标移动导致不必要的行为。我合并了Sawas Dalkitsis answerFuryComptuersanswer以获取以下代码,该代码似乎可以正常工作:

    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);

注意:我没有像Sawas Dalkitsis那样针对ListSelectionModel.SINGLE_INTERVAL_SELECTION进行检查,因此如果在这种情况下实施,请谨慎使用。

答案 3 :(得分:0)

您可以始终使用ListSelectionListener而不是解密点击的点,然后将其翻译为所选项目。

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

在java文件的上述链接中,有一个实现可以很容易地进行“取消选择”:)

答案 4 :(得分:0)

我延长了FuryComptuers个答案以支持多项选择,并解决了setSelectionInterval如果直接调用则无效的问题。

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;
        }
    }   
}

答案 5 :(得分:0)

Nick Dandoulakis' answer在按下 Shift 的同时使用鼠标单击一次选择多个项目时,对我来说不起作用。

以下ListSelectionModel表现为我在使用 Shift Ctrl 鼠标点击选择项目时的预期行为。

另外,按住 Shift + Ctrl 并按按照我想要的方式选择项目。

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();
        }
    }