2014-02-10 2 views
0

Я добавляю меню справки в свою программу, и я пытаюсь выяснить, есть ли способ перехватить ввод с клавиатуры без использования метода setFocusable на JFrame. Это не проблема, если я устанавливаю фокус на фрейм и нажимаю 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

Почему бы просто не использовать обычные программы JMenu? Вы можете добавить мнемонику и ускорители в меню с помощью 'Action'. См. [Пример] (http://stackoverflow.com/a/21583281/2587435) –

+0

@peeskillet Это отличное предложение. – Radiodef

ответ

3

Не используйте KeyListener для этого типа вещей. Как вы заметили, одной из причин является то, что компонент должен быть в фокусе. Вместо этого use a Key Binding с входной картой WHEN_ANCESTOR_OF_FOCUSED_COMPONENT.

Кроме того, некоторые из связанных, см. "The Use of Multiple JFrames, Good/Bad Practice?" Возможно, ваше меню справки должно быть JDialog.

Вот пример использования ключа Binding:

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 должен охватывать, когда сам компонент ориентирован, это не так.

Смежные вопросы