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

……那很有效。 但我不喜欢它。 有没有更好的办法?

在此处查看示例“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; } } }); 

这个怎么样?

 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)单击工作。 我确定它可以修复,但我假设你问这个单选列表……如果不修改你的问题,我们就可以开始考虑多选问题的解决方案了。

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

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

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

不幸的是,这导致许多SO问题上的点击取消选择问题的许多解决方案的exception和冗余调用,包括上面的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的回答解决了这个问题,但是当在所选项目上拖动鼠标时仍然会很奇怪(所选项目将在拖动鼠标时反复选择并取消选择)。 这似乎不是一个问题,但(显然)我有一个颤抖的手,点击时轻微的鼠标移动导致不必要的行为。 我结合了Sawas Dalkitsis的 回答和FuryComptuers的回答来获得以下代码,这似乎符合要求:

  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检查,因此在这种情况下实施时要小心。

您可以始终使用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文件链接中有一个实现,可以很容易地改进来做“取消选择”:)

我扩展了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; } } } 

当按住Shift键的同时使用鼠标点击一次选择多个项目时, Nick Dandoulakis的回答对我来说并不适用。

以下ListSelectionModel在使用带有ShiftCtrl的鼠标点击选择项目时的行为与我期望的一样。

此外,按住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(); } }