2015-03-25 56 views
0

我有一個Swing應用程序與多個窗格。一些窗格是文本窗格(JTextPane),一些是類似對話框(帶有按鈕和滑塊),另一些是圖形(自定義繪製)。我在主菜單中定義了一些簡單的加速器,如KPO如何通過文本窗格隱藏Swing加速器?

我希望這些加速器只有在當前關注的窗格未處理它們時才由菜單操作進行處理。具體來說,我不希望它們在用戶剛剛輸入文本窗格時被菜單處理。

action = new javax.swing.AbstractAction 
new MenuItem(action) 

我註冊加速器具有:

action.putValue(javax.swing.Action.ACCELERATOR_KEY, keyStroke) 

是否有可能「吃」(抑制)的按鍵事件的鍵

我使用創建操作和菜單項在文本窗格中進行處理,以便它們不會傳遞到全局處理的主菜單中?

如果沒有,是否有一些替代方案可以做類似的事情,比如註冊我認爲不應該在某些窗格的文本窗格中處理的加速器?

我加入基於回答的代碼,以使問題更加清晰(並使得開發替代解決方案更容易):

import java.awt.BorderLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.KeyEvent; 

import javax.swing.AbstractAction; 
import javax.swing.Action; 
import javax.swing.JFrame; 
import javax.swing.JMenu; 
import javax.swing.JMenuBar; 
import javax.swing.JScrollPane; 
import javax.swing.JTextArea; 
import javax.swing.JTextField; 
import javax.swing.KeyStroke; 
import javax.swing.WindowConstants; 

public class TestMenuBindings { 

    public static void main(String[] args) { 
     JMenuBar menuBar = new JMenuBar(); 
     final JMenu menu = new JMenu("Print"); 
     final Action oAction = new PrintAction("O",KeyStroke.getKeyStroke(KeyEvent.VK_O, 0)); 
     menu.add(oAction); 
     menuBar.add(menu); 
     JFrame frm = new JFrame("Frame"); 
     frm.setJMenuBar(menuBar); 
     JTextArea area = new JTextArea("Here I want no accelerators", 10, 40); 
     frm.add(new JScrollPane(area)); 
     frm.add(new JTextField("Here I want accelerators working"), BorderLayout.SOUTH); 
     frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     frm.pack(); 
     frm.setVisible(true); 
    } 

    private static class PrintAction extends AbstractAction { 
     private String str; 
     public PrintAction(String aPrintStr, KeyStroke aMnemonic) { 
      super("Print: " + aPrintStr); 
      str = aPrintStr; 
      putValue(Action.ACCELERATOR_KEY, aMnemonic); 
     } 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      System.out.println(str); 
     } 
    } 
} 
+1

當文本組件接收焦點,失去時啓用我只想禁用所有的行動。這將是你的情況下最好的解決方案。 – 2015-03-25 10:43:47

+0

Swing Action hasEnabled [with](否則你可以看看) [EventHandler](http://stackoverflow.com/a/9007348/714968)或(舊的fasioned的方式,但最安全)在運行時添加/刪除通知[一起](http://stackoverflow.com/questions/ 10880326/jpanel-which-one-of-listeners-is-proper-for-visibility-is-change), – mKorbel 2015-03-25 13:40:47

+0

同時,我學到了一些東西:'JTextPane'將事件標記爲已消耗,但問題在於它不同事件發送到主菜單。主菜單發送'KEY_PRESSED',文本窗格發送'KEY_TYPED'。因此,'JTextPane'使用'KEY_PRESSED'對菜單事件沒有影響(還要注意'KEY_PRESSED'事件在'KEY_TYPED'之前排隊)。 – Suma 2015-03-25 15:11:14

回答

0

可以使用KeyEventDispatcher來過濾關鍵事件。

(來源:我已經適應從answer to Application wide keyboard shortcut代碼)

import java.awt.*; 
import java.awt.event.ActionEvent; 
import java.awt.event.KeyEvent; 

import javax.swing.*; 

public class TestMenuBindings { 

    public static void main(String[] args) { 
     JMenuBar menuBar = new JMenuBar(); 
     final JMenu menu = new JMenu("Print"); 
     final Action oAction = new PrintAction("O",KeyStroke.getKeyStroke(KeyEvent.VK_O, 0)); 
     menu.add(oAction); 
     menuBar.add(menu); 
     JFrame frm = new JFrame("Frame"); 
     frm.setJMenuBar(menuBar); 

     final JTextArea area = new JTextArea("Here working no accelerators", 10, 40); 
     frm.add(new JScrollPane(area)); 

     frm.add(new JTextField("Here working accelerators"), BorderLayout.SOUTH); 

     KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); 
     kfm.addKeyEventDispatcher(new KeyEventDispatcher() { 
      @Override 
      public boolean dispatchKeyEvent(KeyEvent e) { 
       KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e); 
       // pass only KEY_TYPED for letters with no modifiers in the editing area, suppress KEY_PRESSED, KEY_RELEASED 
       return area.isFocusOwner() && keyStroke.getModifiers()==0 && e.getID()!=KeyEvent.KEY_TYPED && Character.isLetter(e.getKeyChar()); 
      } 
     }); 

     frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     frm.pack(); 
     frm.setVisible(true); 
    } 

    private static class PrintAction extends AbstractAction { 
     private String str; 
     public PrintAction(String aPrintStr, KeyStroke aMnemonic) { 
      super("Print: " + aPrintStr); 
      str = aPrintStr; 
      putValue(Action.ACCELERATOR_KEY, aMnemonic); 
     } 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      System.out.println(str); 
     } 
    } 
} 
1

這裏是例子。在文本區域沒有鍵綁定工作。在文本字段中處理所有的鍵綁定。此外,菜單中的所有菜單項都可以訪問(啓用)。

import java.awt.BorderLayout; 
import java.awt.Component; 
import java.awt.event.ActionEvent; 
import java.awt.event.FocusEvent; 
import java.awt.event.FocusListener; 
import java.awt.event.KeyEvent; 

import javax.swing.AbstractAction; 
import javax.swing.Action; 
import javax.swing.JFrame; 
import javax.swing.JMenu; 
import javax.swing.JMenuBar; 
import javax.swing.JMenuItem; 
import javax.swing.JScrollPane; 
import javax.swing.JTextArea; 
import javax.swing.JTextField; 
import javax.swing.KeyStroke; 
import javax.swing.WindowConstants; 

public class TestMenuBindings { 

    public static void main(String[] args) { 
     JMenuBar menuBar = new JMenuBar(); 
     final JMenu menu = new JMenu("Print"); 
     menu.add(new PrintAction("O", KeyStroke.getKeyStroke(KeyEvent.VK_O, 0))); 
     menu.add(new PrintAction("K", KeyStroke.getKeyStroke(KeyEvent.VK_K, 0))); 
     menu.add(new PrintAction("P", KeyStroke.getKeyStroke(KeyEvent.VK_P, 0))); 
     menuBar.add(menu); 
     JFrame frm = new JFrame("Frame"); 
     frm.setJMenuBar(menuBar); 
     JTextArea area = new JTextArea("Here working no accelerators", 10, 40); 
     area.addFocusListener(new FocusListener() { 

      @Override 
      public void focusLost(FocusEvent e) { 
       setItemStatus(menu, true); 
      } 

      @Override 
      public void focusGained(FocusEvent e) { 
       setItemStatus(menu, false); 
      } 
     }); 
     frm.add(new JScrollPane(area)); 
     frm.add(new JTextField("Here working accelerators"), BorderLayout.SOUTH); 
     frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     frm.pack(); 
     frm.setVisible(true); 
    } 

    private static void setItemStatus(JMenu aMenu, boolean aStatus) { 
     for (Component item : aMenu.getMenuComponents()) { 
      ((JMenuItem) item).getAction().setEnabled(aStatus); 
     } 
    } 
    private static class PrintAction extends AbstractAction { 
     private String str; 
     public PrintAction(String aPrintStr, KeyStroke aMnemonic) { 
      super("Print: " + aPrintStr); 
      str = aPrintStr; 
      putValue(Action.ACCELERATOR_KEY, aMnemonic); 
     } 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      System.out.println(str); 
     } 
    } 
} 
+0

1+,用於演示問題和解決方案的簡單SSCCE/MVCE。 – camickr 2015-03-26 03:18:32

0

這是一個使用KeyBindinds的解決方案,如camickr所建議的。它比the one provided by Sergiy Medvynskyy短,我覺得它更直接,但它有一個缺點,快捷方式不顯示在菜單中,這是快捷方式未在動作本身中定義的結果。

import java.awt.BorderLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.KeyEvent; 

import javax.swing.AbstractAction; 
import javax.swing.Action; 
import javax.swing.JFrame; 
import javax.swing.JMenu; 
import javax.swing.JMenuBar; 
import javax.swing.JScrollPane; 
import javax.swing.JTextArea; 
import javax.swing.JTextField; 
import javax.swing.KeyStroke; 
import javax.swing.WindowConstants; 

public class TestMenuBindings { 

    public static void main(String[] args) { 
     JMenuBar menuBar = new JMenuBar(); 
     final JMenu menu = new JMenu("Print"); 
     final Action oAction = new PrintAction("O"); 
     menu.add(oAction); 
     menuBar.add(menu); 
     JFrame frm = new JFrame("Frame"); 
     frm.setJMenuBar(menuBar); 
     JTextArea area = new JTextArea("Here working no accelerators", 10, 40); 
     frm.add(new JScrollPane(area)); 
     frm.add(new JTextField("Here working accelerators") { 
      { 
       getInputMap(WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_O, 0), "command_O"); 
       getActionMap().put("command_O", oAction); 
      } 
     }, BorderLayout.SOUTH); 
     frm.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE); 
     frm.pack(); 
     frm.setVisible(true); 
    } 

    private static class PrintAction extends AbstractAction { 
     private String str; 
     public PrintAction(String aPrintStr) { 
      super("Print: " + aPrintStr); 
      str = aPrintStr; 
     } 
     @Override 
     public void actionPerformed(ActionEvent e) { 
      System.out.println(str); 
     } 
    } 
} 
+0

也是一個很好的解決方案,如果你只有幾個組件必須得到加速鍵 – 2015-03-26 10:13:38