2013-04-22 179 views
2

我有一個獨立的基於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

  • 回答

    1

    如果你的問題是如何刪除控制+ 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

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

    補充說明:

    • 不要,如果沒有必要使用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