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
在上面的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
在使用带有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(); } }