我有一个较旧的独立基于java swing的应用程序,它使用JFrame和JMenuBar,包含多个Jmenu元素(带有相应的JMenuItem项目)。
在Windows(7和vista)上升级到最新的1.6.0_41(或1.7.x)JVM后,我注意到带有快捷键Ctrl-C(或Ctrl-Insert)的菜单项没有收到它ActionEvent 如果将JTable添加到框架。如果通过鼠标单击访问菜单,则调用菜单ActionListener。如果删除JTable,则快捷方式有效。如果我将快捷方式组合更改为Ctrl-C或Ctrl-Insert以外的其他组合(即Ctrl-L),则会调用ActionListener。
以前的工作方式(我刚刚在Windows Vista上用jvm 1.4确认了它 - 我知道它已经有一段时间了,因为那个环境得到了认真的关注:)是Ctrl-C会执行标准复制到剪贴板如果焦点位于可编辑字段内,则在JTable内部运行。否则,我的菜单ActionListener是通过setAccelerator()方法分配的快捷方式调用的。
看起来JTable实现在1.6。*中更改为在Windows上以不同方式处理Ctrl-C绑定事件。
在Mac OS(JVM 1.6.0_43)上运行此应用程序我可以看到通过Ctrl-C快捷方式调用ActionListener。虽然可能是因为JTable使用Command-C而不是Ctrl-C来复制到Mac OS下的剪贴板。
我已经提取了演示问题的代码的相关部分。非常感谢任何建议。
public class TestFrame extends JFrame {
public TestFrame(String title) {
super(title);
}
private void init() {
getContentPane().setLayout(new BorderLayout());
addMenu();
addTable();
// Change default exit operation
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
setVisible(true);
}
private void addTable() {
JTable jTable = new JTable(createTableModel());
// Place table in JScrollPane
JScrollPane scrollPane = new JScrollPane(jTable);
// Add Table
add(scrollPane, BorderLayout.CENTER);
}
private TableModel createTableModel() {
Object[][] data = new Object[][]{
{new Date(), "First Row, 2nd column", "First Row, 3rd column"},
{new Date(), "Second Row, 2nd column", "Second Row, 3rd column"},
};
Object[] columnNames = new Object[]{"Date", "Type", "Description"};
DefaultTableModel model = new DefaultTableModel(data, columnNames) {
public boolean isCellEditable(int row, int column) {
return column != 0;
}
};
return model;
}
private void addMenu() {
// Create the menu bar.
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
JMenu editMenu = new JMenu("Edit");
menuBar.add(editMenu);
TestActionListener listener = new TestActionListener();
JMenuItem menuItem = null;
menuItem = new JMenuItem("Copy 1");
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, ActionEvent.CTRL_MASK));
menuItem.addActionListener(listener);
editMenu.add(menuItem);
menuItem = new JMenuItem("Copy 2");
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, ActionEvent.CTRL_MASK));
menuItem.addActionListener(listener);
editMenu.add(menuItem);
menuItem = new JMenuItem("Copy 3");
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, ActionEvent.CTRL_MASK));
menuItem.addActionListener(listener);
editMenu.add(menuItem);
}
public static void main(String[] args) {
TestFrame frame = new TestFrame("Test");
frame.init();
}
private static class TestActionListener implements ActionListener {
public void actionPerformed(ActionEvent e) {
System.out.println("TestFrame.TestActionListener.actionPerformed(): e="+ e);
}
}
}
答案 0 :(得分:2)
问题在于你的框架没有聚焦,整个组件层次结构中没有任何元素具有焦点,这意味着没有人会“抓住”事件并试图用它做一些事情。由于JMenuItem
将其快捷方式绑定到输入地图JComponent.WHEN_IN_FOCUSED_WINDOW
,因此您的快捷方式永远不会“回答”该事件。
要解决此问题,请将焦点放在其中一个组件上,或直接放在JFrame
上(例如使用frame.requestFocusInWindow();
)。这里的小例子:
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.KeyStroke;
import javax.swing.SwingUtilities;
public class TestFrame extends JFrame {
public TestFrame(String title) {
super(title);
}
private void init() {
getContentPane().setLayout(new BorderLayout());
addMenu();
addTable();
// Change default exit operation
setDefaultCloseOperation(EXIT_ON_CLOSE);
pack();
setVisible(true);
}
private void addTable() {
JTable jTable = new JTable();
// Place table in JScrollPane
JScrollPane scrollPane = new JScrollPane(jTable);
// Add Table
add(scrollPane, BorderLayout.CENTER);
}
private void addMenu() {
// Create the menu bar.
JMenuBar menuBar = new JMenuBar();
setJMenuBar(menuBar);
JMenu editMenu = new JMenu("Edit");
menuBar.add(editMenu);
TestActionListener listener = new TestActionListener();
JMenuItem menuItem = null;
menuItem = new JMenuItem("Copy 1");
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_INSERT, KeyEvent.CTRL_MASK));
menuItem.addActionListener(listener);
editMenu.add(menuItem);
menuItem = new JMenuItem("Copy 2");
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, KeyEvent.CTRL_MASK));
menuItem.addActionListener(listener);
editMenu.add(menuItem);
menuItem = new JMenuItem("Copy 3");
menuItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_L, KeyEvent.CTRL_MASK));
menuItem.addActionListener(listener);
editMenu.add(menuItem);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
TestFrame frame = new TestFrame("Test");
frame.init();
frame.requestFocusInWindow();
}
});
}
private static class TestActionListener implements ActionListener {
@Override
public void actionPerformed(ActionEvent e) {
System.out.println("TestFrame.TestActionListener.actionPerformed(): e=" + e);
}
}
}
补充说明:
JFrame
SwingUtilities.invokeLater()
答案 1 :(得分:1)
如果您质疑如何从表中删除Control + C绑定,那么您可以执行以下操作:
KeyStroke copy = KeyStroke.getKeyStroke("control C");
InputMap im = table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
im.getParent().remove(copy);
但是,这将删除所有表的绑定。