制作帮助菜单

时间:2014-02-10 18:23:39

标签: java swing inner-classes keylistener

我正在为我的程序添加一个帮助菜单,我试图找出是否有办法拦截键盘输入,而不必在JFrame上使用setFocusable方法。如果我将焦点设置到框架并按F1,则没有问题。当他们按下任何其他组件时会出现问题。帧不再处于焦点位置,因此F1键不再显示菜单。我是这样做的

package helpmenu;

import java.awt.event.KeyEvent;
import java.awt.event.KeyListener;

import javax.swing.JFrame;

public class HelpMenu extends JFrame
{
    public HelpMenu() 
    {
        setSize(300, 300);
        setTitle("Help Menu");
    }


    /**
     * Sets a KeyListener to
     * the passed in JFrame.
     * @param mainFrame
     */
    public void callMenu( JFrame mainFrame )
    {
        mainFrame.addKeyListener( new functionListener() ); //Set keylistener to the main frame.
        mainFrame.setFocusable(true); //Put the main frame into focus.
    }

    /**
     * Inner KeyListener
     * class for the mainFrame
     * @author Shaun
     */
    class functionListener implements KeyListener
    {
        @Override
        public void keyPressed(KeyEvent e)
        {
            //Check if the F1 key was pressed
            if ( e.getKeyCode() == KeyEvent.VK_F1 ) { 
                setVisible(true);
            }
        }

        @Override
        public void keyReleased(KeyEvent e) {}

        @Override
        public void keyTyped(KeyEvent e) {}
    }
}

1 个答案:

答案 0 :(得分:3)

不要将KeyListener用于此类事情。正如您所注意到的,一个原因是它要求组件成为焦点。而是使用WHEN_ANCESTOR_OF_FOCUSED_COMPONENT输入映射use a Key Binding

另外,有些相关,请参阅"The Use of Multiple JFrames, Good/Bad Practice?"您的帮助菜单应该是JDialog。

以下是使用密钥绑定的示例:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

class HelpDialogEx {
    public static void main(String[] args) {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                new HelpDialogEx();
            }
        });
    }

    final JFrame frame = new JFrame("Press F1 for help");
    final JPanel cpane = new JPanel(new GridLayout(4, 5, 10, 10));

    final HelpDialog help = new HelpDialog(frame);

    final AbstractAction helpToggle = new AbstractAction() {
        @Override
        public void actionPerformed(ActionEvent ae) {
            help.setVisible(!help.isVisible());
        }
    };

    HelpDialogEx() {
        for(int i = 0; i < 20; i++) {
            cpane.add(new JButton("Nil"));
        }

        cpane.setPreferredSize(new Dimension(640, 480));
        frame.setContentPane(cpane);

        addHelpToggle(frame.getRootPane());
        addHelpToggle(help.getRootPane());

        frame.pack();
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }

    void addHelpToggle(JComponent comp) {
        KeyStroke f1Key = KeyStroke.getKeyStroke(
            KeyEvent.VK_F1, 0, true
        );
        String cmd = "helpToggle";

        for(InputMap im : new InputMap[] {
            comp.getInputMap(JComponent.WHEN_FOCUSED),
            comp.getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT)
        }) {
            im.put(f1Key, cmd);
        }

        comp.getActionMap().put(cmd, helpToggle);
    }

    static class HelpDialog
    extends JDialog {
        HelpDialog(Window parent) {
            super(parent, "\"Help\"", Dialog.ModalityType.MODELESS);

            JTextArea doc = new JTextArea(getUnhelpfulText());
            doc.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
            doc.setEditable(false);
            doc.setLineWrap(true);

            JScrollPane scroll = new JScrollPane(doc);
            scroll.getViewport().setPreferredSize(new Dimension(480, 360));

            setContentPane(scroll);

            pack();
            setLocationRelativeTo(null);
        }

        static String getUnhelpfulText() {
            StringBuilder sb = new StringBuilder();

            addRandomParagraph(sb);
            for(int i = 0; i < 3; i++) {
                sb.append("\n\n");
                addRandomParagraph(sb);
            }

            return sb.toString();
        }

        static void addRandomParagraph(StringBuilder sb) {
            sb.append("     ");
            addRandomSentence(sb);
            for(int i = 0; i < 10; i++) {
                sb.append(' ');
                addRandomSentence(sb);
            }
        }

        static void addRandomSentence(StringBuilder sb) {
            sb.append((char)(Math.random() * 26 + 'A'));

            for(int i = (int)(Math.random() * 10 + 1); i > 0; i--) {
                for(int len = (int)(Math.random() * 10 + 1); len > 0; len--) {
                    sb.append((char)(Math.random() * 26 + 'a'));
                }

                sb.append(' ');
            }

            sb.setCharAt(sb.length() - 1, '.');
        }
    }
}

我发现虽然教程说WHEN_ANCESTOR_OF_FOCUSED_COMPONENT应该涵盖组件本身的重点,但事实并非如此。