如何通过文本窗格隐藏Swing加速器?

时间:2015-03-25 09:47:50

标签: java swing focus keyboard-shortcuts

我有一个包含多个窗格的Swing应用程序。一些窗格是文本窗格(JTextPane),有些是对话框(带按钮和滑块),有些是图形(自定义绘制)。我在主菜单中定义了一些操作,使用简单的加速器,如 K P O

我希望仅当当前关注的窗格不处理它们时才通过菜单操作处理这些加速器。具体来说,当用户只是在文本窗格中输入时,我不希望它们被菜单处理。

我正在使用以下方式创建动作和菜单项:

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

3 个答案:

答案 0 :(得分: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);
        }
    }
}

答案 1 :(得分: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);
        }
    }
}

答案 2 :(得分: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);
        }
    }
}