10

“当用户单击列表中的最后一个元素时,有什么方法可以防止 JList 选择最后一个元素?”

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

[编辑]

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

对于一个真实的例子,试试这个JList Swing 教程例子点击空白处,看到 Rollo 被选中。

4

2 回答 2

16

请参阅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);
            }
        });
    }
}
于 2012-06-21T13:19:44.020 回答
3

查看调用堆栈,如果不弄乱 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<E>).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<T>, AccessControlContext) line: not available [native method]    
    ProtectionDomain$1.doIntersectionPrivilege(PrivilegedAction<T>, AccessControlContext, AccessControlContext) line: 76    
    ProtectionDomain$1.doIntersectionPrivilege(PrivilegedAction<T>, 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();
            }
        });
    }
}
于 2012-06-21T13:49:37.617 回答