如何防止JList在单元格边界外进行选择?

“当用户点击列表下面的JList时,有没有办法阻止JList选择最后一个元素?”

这是有人在这里问的问题,我有同样的问题。 那家伙找到了一个马马虎虎的解决方案(通过覆盖processMouseEvent()),但我想知道是否有更好/更优雅的方法来做到这一点。

[编辑]

好的,更多细节。 如果您有一个JList并且有一些空间未被任何单元/元素占用,并且您单击该空格,则JList中的最后一个元素被选中。

有关实际示例,请尝试此JList Swing Tutorial示例 , 单击空白区域并查看已选择Rollo。

请参阅https://forums.oracle.com/forums/thread.jspa?threadID=2206996

 import java.awt.EventQueue; import java.awt.Point; import java.awt.Toolkit; import java.awt.event.InputEvent; import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JScrollPane; public class TestJList { public static void main(String[] args) { EventQueue.invokeLater(new Runnable() { public void run() { JList list = new JList(new Object[] { "One", "Two", "Three" }) { @Override public int locationToIndex(Point location) { int index = super.locationToIndex(location); if (index != -1 && !getCellBounds(index, index).contains(location)) { return -1; } else { return index; } } }; list.addMouseListener(new MouseAdapter() { @Override public void mouseClicked(MouseEvent e) { JList list = (JList) e.getSource(); if (list.locationToIndex(e.getPoint()) == -1 && !e.isShiftDown() && !isMenuShortcutKeyDown(e)) { list.clearSelection(); } } private boolean isMenuShortcutKeyDown(InputEvent event) { return (event.getModifiers() & Toolkit.getDefaultToolkit() .getMenuShortcutKeyMask()) != 0; } }); JFrame frame = new JFrame("Test"); frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); frame.getContentPane().add(new JScrollPane(list)); frame.pack(); frame.setLocationRelativeTo(null); frame.setVisible(true); } }); } } 

看看调用堆栈,如果不弄乱AWT-Events,你就无法真正做到你想做的事情:

 Thread [AWT-EventQueue-0] (Suspended (breakpoint at line 384 in DefaultListSelectionModel)) DefaultListSelectionModel.changeSelection(int, int, int, int, boolean) line: 384 DefaultListSelectionModel.changeSelection(int, int, int, int) line: 415 DefaultListSelectionModel.setSelectionInterval(int, int) line: 459 TestJList$1(JList).setSelectionInterval(int, int) line: 2067 BasicListUI$Handler.adjustSelection(MouseEvent) line: 2739 BasicListUI$Handler.mousePressed(MouseEvent) line: 2695 AWTEventMulticaster.mousePressed(MouseEvent) line: 280 TestJList$1(Component).processMouseEvent(MouseEvent) line: 6502 TestJList$1(JComponent).processMouseEvent(MouseEvent) line: 3321 TestJList$1.processMouseEvent(MouseEvent) line: 24 TestJList$1(Component).processEvent(AWTEvent) line: 6270 TestJList$1(Container).processEvent(AWTEvent) line: 2229 TestJList$1(Component).dispatchEventImpl(AWTEvent) line: 4861 TestJList$1(Container).dispatchEventImpl(AWTEvent) line: 2287 TestJList$1(Component).dispatchEvent(AWTEvent) line: 4687 LightweightDispatcher.retargetMouseEvent(Component, int, MouseEvent) line: 4832 LightweightDispatcher.processMouseEvent(MouseEvent) line: 4489 LightweightDispatcher.dispatchEvent(AWTEvent) line: 4422 JFrame(Container).dispatchEventImpl(AWTEvent) line: 2273 JFrame(Window).dispatchEventImpl(AWTEvent) line: 2713 JFrame(Component).dispatchEvent(AWTEvent) line: 4687 EventQueue.dispatchEventImpl(AWTEvent, Object) line: 707 EventQueue.access$000(EventQueue, AWTEvent, Object) line: 101 EventQueue$3.run() line: 666 EventQueue$3.run() line: 664 AccessController.doPrivileged(PrivilegedAction, AccessControlContext) line: not available [native method] ProtectionDomain$1.doIntersectionPrivilege(PrivilegedAction, AccessControlContext, AccessControlContext) line: 76 ProtectionDomain$1.doIntersectionPrivilege(PrivilegedAction, AccessControlContext) line: 87 EventQueue$4.run() line: 680 EventQueue$4.run() line: 678 

您可以实现自己的ListUI然后做任何你想做的事情(包括防止这种不必要的行为),但我真的不建议沿着那条道路前进。

对于它的价值(通过重写processXXXEvent方法来完成),这里有一个小片段,我实际上发现它不那么难看,并且在单击其边界外时阻止选择对象:

 import java.awt.event.MouseEvent; import javax.swing.JFrame; import javax.swing.JList; import javax.swing.JScrollPane; import javax.swing.SwingUtilities; public class TestJList { private JList list; protected void initUI() { JFrame frame = new JFrame("test"); list = new JList(new Object[] { "Hello", "World", "!" }) { private boolean processEvent(MouseEvent e) { int index = list.locationToIndex(e.getPoint()); return index > -1 && list.getCellBounds(index, index).contains(e.getPoint()); } @Override protected void processMouseEvent(MouseEvent e) { if (processEvent(e)) { super.processMouseEvent(e); } } @Override protected void processMouseMotionEvent(MouseEvent e) { if (processEvent(e)) { super.processMouseMotionEvent(e); } } }; list.setVisibleRowCount(10); frame.add(new JScrollPane(list)); frame.pack(); frame.setVisible(true); } public static void main(String[] args) { SwingUtilities.invokeLater(new Runnable() { @Override public void run() { new TestJList().initUI(); } }); } }