仅当我按下键盘上的菜单键时,JPopupMenu 才会跳几行
JPopupMenu jumps few rows only when I press Menu key on keyboard
这很奇怪。当我使用鼠标右键单击时,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
我更进一步,向 table 添加了 20 行,然后缩小框架以便显示滚动条。
弹出窗口始终显示在视口中间。
这作为默认行为是有意义的,因为弹出窗口可以显示在任何组件上。弹出窗口不知道视口中有具有选择逻辑的组件。
以下代码尝试根据是使用鼠标还是键盘显示弹出窗口来自定义 popup/selection 行为:
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) );
}
}
当使用鼠标时,选择将被更改,弹出窗口将显示在鼠标位置。
使用键盘时,弹出位置基于当前选定的单元格。
这很奇怪。当我使用鼠标右键单击时,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
我更进一步,向 table 添加了 20 行,然后缩小框架以便显示滚动条。
弹出窗口始终显示在视口中间。
这作为默认行为是有意义的,因为弹出窗口可以显示在任何组件上。弹出窗口不知道视口中有具有选择逻辑的组件。
以下代码尝试根据是使用鼠标还是键盘显示弹出窗口来自定义 popup/selection 行为:
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) );
}
}
当使用鼠标时,选择将被更改,弹出窗口将显示在鼠标位置。
使用键盘时,弹出位置基于当前选定的单元格。