2012-11-26 34 views
3

我創建了一個接收Action的JButton類,JButton類包含擊鍵&鼠標偵聽器,所以我可以根據需要在多個框架中使用相同的類。JButton&Action&KeyBinding

我的問題是: 當按鍵時,JButton沒有得到焦點,但它正在執行操作。 我需要創建一個新的背景或告訴用戶按鈕執行了操作。

任何想法??

這裏是我的代碼:

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Insets; 
import java.awt.event.KeyEvent; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import javax.swing.Action; 
import javax.swing.JButton; 
import javax.swing.JComponent; 
import javax.swing.KeyStroke; 
import javax.swing.SwingConstants; 
import javax.swing.border.LineBorder; 
import swtdesigner.SwingResourceManager; 

public class IButtonSave extends JButton{ 
    private static final long serialVersionUID = 1L; 
    private Action action = null; 
    public IButtonSave() { 
     super(); 
     setFocusPainted(true); 
     setFocusable(true); 

     try { 
      jbInit(); 
     } catch (Throwable e) { 
      e.printStackTrace(); 
     } 
    } 

    private void jbInit() throws Exception { 
     setMargin(new Insets(0, 0, 0, 0)); 
     setBorder(new LineBorder(Color.black, 1, true)); 
     setIconTextGap(0); 
     setHorizontalTextPosition(SwingConstants.CENTER); 
     setVerticalTextPosition(SwingConstants.TOP); 
     setPreferredSize(new Dimension(50, 43)); 
     setMinimumSize(new Dimension(50, 43)); 
     setMaximumSize(new Dimension(50, 43)); 
     addMouseListener(new ThisMouseListener()); 
     setVerifyInputWhenFocusTarget(true); 
    } 

    public void setAction(Action a){ 
     action = a; 
     KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_F1,0,true); 
     KeyStroke ks2 = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER,0); 
     getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ks, "Save"); 
     getInputMap(JComponent.WHEN_FOCUSED).put(ks2, "Save"); 

     getActionMap().put("Save", a); 
     setText("Save [F1]"); 
     setIcon(SwingResourceManager.getIcon(SwingResourceManager.class, "/images/small/save.png")); 
     setToolTipText("[F1]"); 
    } 

    private class ThisMouseListener extends MouseAdapter { 
     public void mouseClicked(MouseEvent e) { 
      this_mouseClicked(e); 
     } 
    } 
    protected void this_mouseClicked(MouseEvent e) { 
     if(e.getClickCount() >= 1){ 
      action.actionPerformed(null); 
     } 
    } 
} 
+0

不調用'super.setAction'的任何原因? –

+0

不,在您的方式調用它沒有問題,按鈕工作得很好,但按F1鍵時,操作完成,但焦點永遠不會去按鈕。我需要做的是在執行操作時使按鈕成爲焦點並按下。 – Motasem

+0

爲了更快提供更好的幫助,請發佈[SSCCE](http://sscce.org/)(該示例至少需要一個'main(String [])'在屏幕上的選項窗格中顯示一個'IButtonSave') 。 –

回答

5

爲什麼要擴展JButton上課的時候,你可以簡單地添加KeyBinding s到它的實例?

不要相信你想要什麼,但能正常工作對我來說:

基本上是一個JButton可以通過鼠標點擊來激活,或按F1(只要重點是窗口,如果按下將轉向重點爲JButton)或輸入(僅當焦點JButton時)。

AbstractAction被調用時,它將呼籲JButtonrequestFocusInWindow()(因此按F1將使按鈕獲取焦點是什麼,我想你想):

enter image description here

import java.awt.BorderLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.KeyEvent; 
import javax.swing.AbstractAction; 
import javax.swing.JButton; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JTextField; 
import javax.swing.KeyStroke; 
import javax.swing.SwingUtilities; 

public class Test { 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       JFrame frame = new JFrame(); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

       final JButton btn = new JButton("Button"); 

       AbstractAction aa = new AbstractAction() { 
        @Override 
        public void actionPerformed(ActionEvent ae) { 
         System.out.println("Here"); 

         btn.requestFocusInWindow();//request that the button has focus 
        } 
       }; 

       //so button can be pressed using F1 and ENTER 
       btn.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "Enter"); 
       btn.getActionMap().put("Enter", aa); 
       btn.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0), "F1"); 
       btn.getActionMap().put("F1", aa); 

       btn.addActionListener(aa);//so button can be clicked 

       JTextField tf = new JTextField("added to show ENTER wont work unless button in focus"); 

       frame.add(tf); 
       frame.add(btn, BorderLayout.SOUTH); 

       frame.pack(); 
       frame.setVisible(true); 
      } 
     }); 
    } 
} 

UPADTE:

或者作爲@GuillaumePolet建議(+1他)覆蓋的JButtonprocessKeyBinding,並檢查相應的密鑰和調用方法:

import java.awt.BorderLayout; 
import java.awt.event.ActionEvent; 
import java.awt.event.KeyEvent; 
import javax.swing.AbstractAction; 
import javax.swing.JButton; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JTextField; 
import javax.swing.KeyStroke; 
import javax.swing.SwingUtilities; 

public class Test { 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       final JFrame frame = new JFrame(); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

       final JButton btn = new JButton("Button") { 
        @Override 
        protected boolean processKeyBinding(KeyStroke ks, KeyEvent ke, int i, boolean bln) { 
         boolean b = super.processKeyBinding(ks, ke, i, bln); 

         if (b && ks.getKeyCode() == KeyEvent.VK_F1) { 
          requestFocusInWindow(); 
         } 

         return b; 
        } 
       }; 

       AbstractAction aa = new AbstractAction() { 
        @Override 
        public void actionPerformed(ActionEvent ae) { 
         System.out.println("Here"); 
        } 
       }; 

       //so button can be pressed using F1 and ENTER 
       btn.getInputMap(JComponent.WHEN_FOCUSED).put(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0), "Enter"); 
       btn.getActionMap().put("Enter", aa); 
       btn.getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0), "F1"); 
       btn.getActionMap().put("F1", aa); 

       btn.addActionListener(aa);//so button can be clicked 

       JTextField tf = new JTextField("added to show ENTER wont work unless button in focus"); 

       frame.add(tf); 
       frame.add(btn, BorderLayout.SOUTH); 

       frame.pack(); 
       frame.setVisible(true); 
      } 
     }); 
    } 
} 
+0

助記符必須與L&F無鼠標修飾符(通常是Alt鍵)結合使用。此外,行動可以直接設置在JButton而不是手動處理所有這些或使用ActionListener –

+0

這是正確的100%,但如果你按F1按鈕將不會集中 – Motasem

+0

@Motasem因爲它不應該如果你想這發生只是調用' requestFocusInWindow()'在按鈕實例 –

3

不知道這是做的最好的方式,但它工作體面足夠的,如果它是不是最好的方法,你從這個答案中獲得一個免費的SSCCE

我重寫processKeyBindings(),如果它返回true,那麼我抓住焦點來表明該操作已執行。如果你想做別的事情,你只需要在那裏修改代碼。

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.JButton; 
import javax.swing.JComponent; 
import javax.swing.JFrame; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.JTextArea; 
import javax.swing.KeyStroke; 
import javax.swing.SwingUtilities; 

public class IButtonSave extends JButton { 
    private static final long serialVersionUID = 1L; 

    public IButtonSave() { 
     super(); 
     setFocusPainted(true); 
     setFocusable(true); 
    } 

    @Override 
    protected boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) { 
     boolean processKeyBinding = super.processKeyBinding(ks, e, condition, pressed); 
     if (processKeyBinding) { 
      requestFocusInWindow(); 
     } 
     return processKeyBinding; 
    } 

    @Override 
    public void setAction(Action a) { 
     super.setAction(a); 
     KeyStroke ks = KeyStroke.getKeyStroke(KeyEvent.VK_F1, 0, true); 
     KeyStroke ks2 = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, 0); 
     getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW).put(ks, "Save"); 
     getInputMap(JComponent.WHEN_FOCUSED).put(ks2, "Save"); 
     getActionMap().put("Save", a); 
     setText("Save [F1]"); 
     setToolTipText("[F1]"); 
    } 

    protected void initUI() { 
     JFrame frame = new JFrame(IButtonSave.class.getSimpleName()); 
     frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
     JTextArea textarea = new JTextArea(5, 30); 
     JPanel buttonPanel = new JPanel(); 
     AbstractAction someAction = new AbstractAction() { 

      @Override 
      public void actionPerformed(ActionEvent e) { 
       System.err.println("Action performed"); 
      } 
     }; 
     IButtonSave button = new IButtonSave(); 
     button.setAction(someAction); 
     buttonPanel.add(button); 
     frame.add(new JScrollPane(textarea)); 
     frame.add(buttonPanel, BorderLayout.SOUTH); 
     frame.pack(); 
     frame.setVisible(true); 
    } 

    public static void main(String[] args) { 
     SwingUtilities.invokeLater(new Runnable() { 
      @Override 
      public void run() { 
       new IButtonSave().initUI(); 
      } 
     }); 
    } 

} 
+0

+1覆蓋'processKeyBinding' –

+0

Thaaaaaaaaaanks,這真的幫助我不知道如何謝謝你。 – Motasem