2008-09-19 71 views
27

Tôi muốn tạo lối tắt bàn phím ứng dụng rộng cho ứng dụng Java Swing. Looping trên tất cả các thành phần và thêm các phím tắt trên mỗi, có tác dụng phụ liên quan đến tập trung, và có vẻ như một giải pháp bạo lực.Phím tắt ứng dụng rộng - Java Swing

Có ai có giải pháp sạch hơn không?

Trả lời

20

Cài đặt KeyEventDispatcher tùy chỉnh. Lớp KeyboardFocusManager cũng là một nơi tốt cho chức năng này.

KeyEventDispatcher

37

Đối với mỗi cửa sổ, sử dụng JComponent.registerKeyboardAction với một điều kiện của WHEN_IN_FOCUSED_WINDOW. Hoặc sử dụng:

JComponent.getInputMap(WHEN_IN_FOCUSED_WINDOW).put(keyStroke, command); 
JComponent.getActionMap().put(command,action); 

như được mô tả trong registerKeyboardAction API docs.

+0

+1 tốt nhất, câu trả lời đơn giản nhất tôi đã tìm thấy. Tôi sẽ upvote x1000 –

+3

x1001 này sẽ tốt hơn, theo cách đó anh ta ít nhất sẽ có được một upvote. – Epaga

+0

@Epaga Hoặc 999 lần –

6

Khi bạn có một trình đơn, bạn có thể thêm phím tắt toàn cầu để các mục menu:

JMenuItem item = new JMenuItem(action); 
    KeyStroke key = KeyStroke.getKeyStroke(
     KeyEvent.VK_R, KeyEvent.CTRL_DOWN_MASK); 
    item.setAccelerator(key); 
    menu.add(item); 
13

Đối với những người tự hỏi (như tôi) làm thế nào để sử dụng KeyEventDispatcher, đây là một ví dụ mà tôi đặt lại với nhau. Nó sử dụng một HashMap để lưu trữ tất cả các hành động toàn cầu, bởi vì tôi không thích các cấu trúc lớn if (key == ..) then .. else if (key == ..) then .. else if (key ==..) ...

/** map containing all global actions */ 
private HashMap<KeyStroke, Action> actionMap = new HashMap<KeyStroke, Action>(); 

/** call this somewhere in your GUI construction */ 
private void setup() { 
    KeyStroke key1 = KeyStroke.getKeyStroke(KeyEvent.VK_A, KeyEvent.CTRL_DOWN_MASK); 
    actionMap.put(key1, new AbstractAction("action1") { 
    @Override 
    public void actionPerformed(ActionEvent e) { 
     System.out.println("Ctrl-A pressed: " + e); 
    } 
    }); 
    // add more actions.. 

    KeyboardFocusManager kfm = KeyboardFocusManager.getCurrentKeyboardFocusManager(); 
    kfm.addKeyEventDispatcher(new KeyEventDispatcher() { 

    @Override 
    public boolean dispatchKeyEvent(KeyEvent e) { 
     KeyStroke keyStroke = KeyStroke.getKeyStrokeForEvent(e); 
     if (actionMap.containsKey(keyStroke)) { 
     final Action a = actionMap.get(keyStroke); 
     final ActionEvent ae = new ActionEvent(e.getSource(), e.getID(), null); 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
      a.actionPerformed(ae); 
      } 
     }); 
     return true; 
     } 
     return false; 
    } 
    }); 
} 

Việc sử dụng SwingUtils.invokeLater() có thể không cần thiết, nhưng có lẽ không nên chặn vòng lặp sự kiện toàn cầu.

+0

Không phải là giải pháp đơn giản nhất, nhưng chắc chắn là giải pháp thanh lịch và đáng tin cậy nhất. –

-1

Sử dụng đoạn mã sau

ActionListener a=new ActionListener(){ 
    public void actionPerformed(ActionEvent ae) 
    { 
    // your code 
    } 
}; 
getRootPane().registerKeyboardAction(a,KeyStroke.getKeyStroke("ctrl D"),JComponent.WHEN_IN_FOCUSED_WINDOW); 

Thay thế "ctrl D" với các phím tắt mà bạn muốn.

+0

không, đó là lỗi thời api (superceded bởi actionMap/inputMap từ jdk 1.2 hoặc 1.3 - cách trở lại trong thời đại đá) – kleopatra

+0

@kleopatra Hmm. Cảm ơn bạn đã bình luận. Tôi muốn biết lý do. Tôi không tìm thấy nó! – user12458

+0

không hoàn toàn hiểu - lý do gì? – kleopatra

1

Một chút ví dụ đơn giản:

KeyboardFocusManager keyManager; 

keyManager=KeyboardFocusManager.getCurrentKeyboardFocusManager(); 
keyManager.addKeyEventDispatcher(new KeyEventDispatcher() { 

    @Override 
    public boolean dispatchKeyEvent(KeyEvent e) { 
    if(e.getID()==KeyEvent.KEY_PRESSED && e.getKeyCode()==27){ 
     System.out.println("Esc"); 
     return true; 
    } 
    return false; 
    } 

}); 
Các vấn đề liên quan