JMenuItem快捷键Ctrl-C/Ctrl-V或Ctrl-Insert/Shift-Insert不再工作
我有一个独立的基于java swing的应用程序,它使用带有JMenuBar的JFrame包含多个Jmenu元素(使用各自的JMenuItem项)。JMenuItem快捷键Ctrl-C/Ctrl-V或Ctrl-Insert/Shift-Insert不再工作
在Windows(7和Vista)上升级到最新的1.6.0_41(或1.7.x)JVM后,我注意到使用快捷键Ctrl-C(或Ctrl-Insert)的菜单项没有收到其行动事件如果JTable被添加到框架。然而,如果通过鼠标点击来访问菜单,则调用菜单ActionListener。如果JTable被删除,捷径就可以工作。如果我将快捷键组合更改为除Ctrl-C或Ctrl-Insert(即Ctrl-L)以外的其他值,则会调用ActionListener。 (我刚刚在Windows Vista上用jvm 1.4确认了它 - 我知道它已经有一段时间了,因为这个环境得到了任何严重的关注:)是Ctrl-C将执行标准拷贝到如果焦点位于可编辑字段的内部,则JTable内部的剪贴板功能。否则,我的菜单ActionListener通过setAccelerator()方法分配的快捷方式调用。
它看起来像1.6中的JTable实现更改*,以便在Windows上以不同方式处理Ctrl-C绑定事件。
在Mac OS上运行此应用程序(JVM 1.6.0_43)我可以看到ActionListener是通过Ctrl-C快捷方式调用的。虽然这可能是因为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);
}
}
}
如果你的问题是如何删除控制+ C从表绑定,那么你可以这样做:
KeyStroke copy = KeyStroke.getKeyStroke("control C");
InputMap im = table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
im.getParent().remove(copy);
然而,这将删除所有表的结合。
这使得总体感觉。我认为问题在于增加了JTable的增强功能,可将选定表格行的内容复制到剪贴板中。并且该动作绑定到Ctrl-C/Ctrl-Insert,它拦截了我为JMenu定义的操作准备的键绑定。它解释了为什么其他键组合工作,但不是Ctrl-C。感谢您使用此解决方案来禁用行内容复制,但仍允许将可编辑的单元格内容复制到剪贴板,而这正是它之前的工作原理。 – pavel 2013-04-23 01:32:22
是否有执行这两个操作的方法? JTable的动作侦听器是否可以接收Ctrl-C事件和我的JMenu?我的自定义Jmenu操作将复制底层模型行,但不会影响正在复制到剪贴板的文本行内容。我可以看到剪贴板中的行内容有时会有帮助。 – pavel 2013-04-23 01:37:42
仅将事件分派给单个组件。我不知道如何将它分派给多个组件。 – camickr 2013-04-23 04:11:12
问题是你的框架没有被关注,你的整个组件层次结构中没有任何元素具有焦点,这意味着没有人会“抢”事件并尝试使用它。由于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);
}
}
}
补充说明:
- 不要,如果没有必要使用
SwingUtilities.invokeLater()
我有一个想法,为什么只有Ctrl-C/Ctrl-Insert会导致问题。在版本1.4.x之后的某个时候,增强了JTable以将所选表格行的内容复制到剪贴板。并且该动作绑定到Ctrl-C/Ctrl-Insert,它拦截了我为JMenu定义的操作准备的键绑定。它解释了为什么其他键组合工作,但不是Ctrl-C。如果表格不是空的,那么调焦框架无助于解决问题。我已经更新了原始代码以包含测试数据模型,以证明问题仍然存在。 – pavel 2013-04-23 01:02:30
JFrame
使用'getMenuShortcutKeyMask()',见[这里](http://stackoverflow.com/a/5129757/230513)。 – trashgod 2013-04-22 09:46:51