java - 仅当我按键盘上的菜单键时,JPopupMenu 才跳转几行

标签 java swing jpopupmenu

这很奇怪。当我使用鼠标右键单击时,JPopMenu 按预期工作。但是当我尝试使用键盘上的菜单键显示它时,突出显示会在之前或之后跳跃几行。

我使用了 PopupMenuListener,以便在使用右键单击时可以直接突出显示一行:

popupMenu.addPopupMenuListener(new PopupMenuListener() {
            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        Point point = SwingUtilities.convertPoint(popupMenu, new Point(0, 0), table);
                        int currentRow = table.rowAtPoint(point);
                        int currentColumn = table.columnAtPoint(point);
                        table.changeSelection(currentRow, currentColumn, false, false);
                    }
                });
            }

            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                // TODO Auto-generated method stub
            }

            @Override
            public void popupMenuCanceled(PopupMenuEvent e) {
                // TODO Auto-generated method stub
            }
        });

这是完整的程序:

import java.awt.Point;

import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;

import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

public class Test {

    private JFrame frame;
    private JTable table;
    private JScrollPane scrollpane;

    public Test() {
        initialize();
    }

    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 450, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        
        String[] head = {"ID","NAME","DOB"};
        
        String[][] data = {
                {"1", "Peter", "2001/03/24"},
                {"2", "Carlos", "1996/09/02"},
                {"3", "Ahmed", "1999/07/07"},
                {"4", "John", "1993/10/15"},
                {"5", "Kumar", "1991/11/08"}
        };
        
        table = new JTable(data, head);
        scrollpane = new JScrollPane(table);
        table.setDefaultEditor(Object.class, null);
        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
        
        JPopupMenu popupMenu = new JPopupMenu();
        JMenuItem edit = new JMenuItem("Edit");
        JMenuItem delete = new JMenuItem("Delete");
        popupMenu.add(edit);
        popupMenu.add(delete);
        table.setComponentPopupMenu(popupMenu);
        
        popupMenu.addPopupMenuListener(new PopupMenuListener() {
            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent e) {
                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run() {
                        Point point = SwingUtilities.convertPoint(popupMenu, new Point(0, 0), table);
                        int currentRow = table.rowAtPoint(point);
                        int currentColumn = table.columnAtPoint(point);
                        table.changeSelection(currentRow, currentColumn, false, false);
                    }
                });
            }

            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                // TODO Auto-generated method stub
            }

            @Override
            public void popupMenuCanceled(PopupMenuEvent e) {
                // TODO Auto-generated method stub
            }
        });
        
        frame.getContentPane().add(scrollpane);
    }
    
    public void setVisible(boolean state) {
        frame.setVisible(state);
    }

}

最佳答案

the selection jumps few records after or before the selected row

我更进一步,向表格中添加了 20 行,然后缩小框架以便显示滚动条。

弹出窗口始终显示在视口(viewport)的中间。

这作为默认行为是有意义的,因为弹出窗口可以显示在任何组件上。弹出窗口不知道视口(viewport)中存在具有选择逻辑的组件。

以下代码尝试根据是否使用鼠标或键盘显示弹出窗口来自定义弹出窗口/选择行为:

import java.awt.*;
import java.awt.event.*;

import javax.swing.JFrame;
import javax.swing.JMenuItem;
import javax.swing.JPopupMenu;
import javax.swing.JScrollPane;

import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.SwingUtilities;
import javax.swing.event.PopupMenuEvent;
import javax.swing.event.PopupMenuListener;

public class Test {

    private JFrame frame;
    private JTable table;
    private JScrollPane scrollpane;

    public Test() {
        initialize();
    }

    private void initialize() {
        frame = new JFrame();
        frame.setBounds(100, 100, 450, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        String[] head = {"ID","NAME","DOB"};

        String[][] data = {
                {"1", "Peter", "2001/03/24"},
                {"2", "Carlos", "1996/09/02"},
                {"3", "Ahmed", "1999/07/07"},
                {"3", "Ahmed", "1999/07/07"},
                {"3", "Ahmed", "1999/07/07"},
                {"3", "Ahmed", "1999/07/07"},
                {"3", "Ahmed", "1999/07/07"},
                {"3", "Ahmed", "1999/07/07"},
                {"3", "Ahmed", "1999/07/07"},
                {"3", "Ahmed", "1999/07/07"},
                {"3", "Ahmed", "1999/07/07"},
                {"3", "Ahmed", "1999/07/07"},
                {"3", "Ahmed", "1999/07/07"},
                {"3", "Ahmed", "1999/07/07"},
                {"3", "Ahmed", "1999/07/07"},
                {"3", "Ahmed", "1999/07/07"},
                {"3", "Ahmed", "1999/07/07"},
                {"4", "John", "1993/10/15"},
                {"5", "Kumar", "1991/11/08"}
        };

        table = new JTable(data, head);
        scrollpane = new JScrollPane(table);
        table.setDefaultEditor(Object.class, null);
        table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);

        JPopupMenu popupMenu = new JPopupMenu();
        JMenuItem edit = new JMenuItem("Edit");
        JMenuItem delete = new JMenuItem("Delete");
        popupMenu.add(edit);
        popupMenu.add(delete);
        table.setComponentPopupMenu(popupMenu);

        popupMenu.addPopupMenuListener(new PopupMenuListener()
        {
            private boolean isMouse;

            @Override
            public void popupMenuWillBecomeVisible(PopupMenuEvent e)
            {
                isMouse = EventQueue.getCurrentEvent().getID() == MouseEvent.MOUSE_RELEASED;

                SwingUtilities.invokeLater(new Runnable() {
                    @Override
                    public void run()
                    {
                        if (isMouse) // change row/cell selection
                        {
                            Point point = SwingUtilities.convertPoint(popupMenu, new Point(0, 0), table);
                            int currentRow = table.rowAtPoint(point);
                            int currentColumn = table.columnAtPoint(point);
                            table.changeSelection(currentRow, currentColumn, false, false);
                        }
                        else  // use current selection
                        {
                            int selectedRow = table.getSelectedRow();
                            int selectedColumn = table.getSelectedColumn();

                            if (selectedRow == -1) // no row selected
                            {
                                popupMenu.setVisible( false );
                            }
                            else  // reset popup location to selected row
                            {
                                Rectangle bounds = table.getCellRect(selectedRow, selectedColumn, false);
                                popupMenu.show(table, bounds.x, bounds.y + bounds.height);
                            }
                        }
                    }
                });
            }

            @Override
            public void popupMenuWillBecomeInvisible(PopupMenuEvent e) {
                // TODO Auto-generated method stub
            }

            @Override
            public void popupMenuCanceled(PopupMenuEvent e) {
                // TODO Auto-generated method stub
            }
        });

        frame.getContentPane().add(scrollpane);
    }

    public void setVisible(boolean state) {
        frame.setVisible(state);
    }

    public static void main(String[] args) throws Exception
    {
        java.awt.EventQueue.invokeLater( () -> new Test().setVisible(true) );
    }
}

当使用鼠标时,选择将发生变化,并且弹出窗口将显示在鼠标位置。

使用键盘时,弹出位置基于当前选定的单元格。

关于java - 仅当我按键盘上的菜单键时,JPopupMenu 才跳转几行,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/68740814/

相关文章:

java - bean 类 [Country] : Bean property 'name' is not writable or has an invalid setter method. 的属性 'name' 无效 您的意思是 'cname' 吗?

java - 是否可以取消网络浏览器的装饰?

java - 我如何用java制作蛇与梯子游戏的棋盘?

java - Netbeans JPopupMenu 问题

java - Spring 可缓存除非条件不起作用

java - 在单例类中添加两个整数值

java - Ear启动后调用方法

java - 如何删除 jtextfield 创建的附加行

java - 防止按下 ALT 时 JPopupMenu 关闭