java - JMenuItem 快捷键 Ctrl-C/Ctrl-V 或 Ctrl-Insert/Shift-Insert 不再起作用

标签 java swing jtable copy-paste jmenu

我有一个较旧的基于 java swing 的独立应用程序,它使用 JFrame 和 JMenuBar,其中包含多个 Jmenu 元素(带有各自的 JMenuItem 项)。

在 Windows(7 和 vista)上升级到最新的 1.6.0_41(或 1.7.x)JVM 后,我注意到带有快捷键 Ctrl-C(或 Ctrl-Insert)的菜单项没有收到其如果 JTable 添加到框架,则不再有 ActionEvent。然而,如果通过鼠标单击访问菜单,则会调用菜单 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 绑定(bind)事件。

在 Mac OS (JVM 1.6.0_43) 上运行此应用程序,我可以看到 ActionListener 是通过 Ctrl-C 快捷方式调用的。虽然这可能是因为 Mac OS 下 JTable 使用 Command-C 而不是 Ctrl-C 复制到剪贴板。

我已经提取了演示该问题的代码的相关部分。非常感谢任何建议。

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

}

最佳答案

问题是你的框架没有聚焦,并且整个组件层次结构中没有任何元素具有焦点,这意味着没有人会“捕获”事件并尝试用它做某事。由于 JMenuItem 将其快捷方式绑定(bind)到输入映射 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() 从事件调度线程 (EDT) 启动您的 UI

关于java - JMenuItem 快捷键 Ctrl-C/Ctrl-V 或 Ctrl-Insert/Shift-Insert 不再起作用,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/16138826/

相关文章:

java - 从代码中获取 SelectOneMenu 的所选项目

java - 为什么随机数会使我的 Android 应用程序崩溃?

Java - JLabel 的 HTML 标签

java - 使来自 JPanel 的图形在 JPanel 外部可见

java - 在 JTable 中,编辑单元格唯一的 JComboBox 时更新显示的项目

java - 在 junit 测试中比较 tar 存档的最佳方法是什么

java - 查找 ArrayList<Object> 中的特定类型(即 Object = String 等)

swing - 在 Netbeans swing gui builder 中为 jFrame 设置图标

java - 如何保存 JTable 列的宽度、顺序和可见性

java - 使用自定义 TableCellRenderer 的 Swing JTable