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

}

+1

  • 从事件指派线程(EDT)开始你的UI扩展JFrame使用'getMenuShortcutKeyMask()',见[这里](http://stackoverflow.com/a/5129757/230513)。 – trashgod 2013-04-22 09:46:51
  • 如果你的问题是如何删除控制+ C从表绑定,那么你可以这样做:

    KeyStroke copy = KeyStroke.getKeyStroke("control C"); 
    InputMap im = table.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); 
    im.getParent().remove(copy); 
    

    然而,这将删除所有表的结合。

    +0

    这使得总体感觉。我认为问题在于增加了JTable的增强功能,可将选定表格行的内容复制到剪贴板中。并且该动作绑定到Ctrl-C/Ctrl-Insert,它拦截了我为JMenu定义的操作准备的键绑定。它解释了为什么其他键组合工作,但不是Ctrl-C。感谢您使用此解决方案来禁用行内容复制,但仍允许将可编辑的单元格内容复制到剪贴板,而这正是它之前的工作原理。 – pavel 2013-04-23 01:32:22

    +0

    是否有执行这两个操作的方法? JTable的动作侦听器是否可以接收Ctrl-C事件和我的JMenu?我的自定义Jmenu操作将复制底层模型行,但不会影响正在复制到剪贴板的文本行内容。我可以看到剪贴板中的行内容有时会有帮助。 – pavel 2013-04-23 01:37:42

    +0

    仅将事件分派给单个组件。我不知道如何将它分派给多个组件。 – 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()
    +0

    我有一个想法,为什么只有Ctrl-C/Ctrl-Insert会导致问题。在版本1.4.x之后的某个时候,增强了JTable以将所选表格行的内容复制到剪贴板。并且该动作绑定到Ctrl-C/Ctrl-Insert,它拦截了我为JMenu定义的操作准备的键绑定。它解释了为什么其他键组合工作,但不是Ctrl-C。如果表格不是空的,那么调焦框架无助于解决问题。我已经更新了原始代码以包含测试数据模型,以证明问题仍然存在。 – pavel 2013-04-23 01:02:30