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

Posted

技术标签:

【中文标题】如何防止 JList 在单元格边界之外进行选择?【英文标题】:How to prevent JList from making selection outside cell bounds? 【发布时间】:2012-06-23 17:13:19 【问题描述】:

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

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

[编辑]

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

举个真实的例子试试这个JList Swing Tutorial example,点击空白处,看看Rollo被选中了。

【问题讨论】:

SO 不是代码生成器,为了获得更好的帮助,请尽快发布SSCCE,否则我的答案很广泛,因为您的问题很简单consume @GuillaumePolet thnx,完全忽略了这方面 @mKorbel 添加了简单示例 【参考方案1】:

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

【讨论】:

+1 优秀代码,由 OTN 上的两位发帖者提供,请查看 Swing API 中所有内置 putClientProperty(...) 的列表 考虑在答案下方阅读 Kleopatra 的评论。清除选择可能有点不方便。我的期望是什么都不会发生。如果我之前做了一个有效的选择(不一定是最后一个单元格),然后我在 JList 外部单击,我希望选择保留,而不是被清除【参考方案2】:

查看调用堆栈,如果不弄乱 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 方法完成的),这里有一个小 sn-p,我实际上发现它并不难看,并且可以防止在超出范围点击时选择对象:

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

【讨论】:

以上是关于如何防止 JList 在单元格边界之外进行选择?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 UICollectionViewCell 的可触摸区域扩展到其边界之外?

将 UIImageView 添加到单元格边界之外的 UITableViewCell

iOS:如何让 UITableView 将其单元格绘制出边界?

防止 UITableView 超出单元格绑定视图在 insertRowsAtIndexPaths 上剪辑:

推送标题部分项目后如何防止单元格编辑?

防止在外部单击时以弹出模式关闭单元格编辑器