Mega Code Archive

 
Categories / Java Tutorial / Swing
 

Transfer focus from button to button with help of arrows keys

/*  * Copyright 2006 Sun Microsystems, Inc., 4150 Network Circle,  * Santa Clara, California 95054, U.S.A. All rights reserved.  *  * This library is free software; you can redistribute it and/or  * modify it under the terms of the GNU Lesser General Public  * License as published by the Free Software Foundation; either  * version 2.1 of the License, or (at your option) any later version.  *  * This library is distributed in the hope that it will be useful,  * but WITHOUT ANY WARRANTY; without even the implied warranty of  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU  * Lesser General Public License for more details.  *  * You should have received a copy of the GNU Lesser General Public  * License along with this library; if not, write to the Free Software  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA  */ import java.awt.BorderLayout; import java.awt.Component; import java.awt.Container; import java.awt.FocusTraversalPolicy; import java.awt.GridLayout; import java.awt.KeyboardFocusManager; import java.awt.LayoutManager; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.InputEvent; import java.awt.event.KeyEvent; import javax.swing.AbstractButton; import javax.swing.BorderFactory; import javax.swing.ButtonGroup; import javax.swing.ButtonModel; import javax.swing.DefaultButtonModel; import javax.swing.JButton; import javax.swing.JCheckBox; import javax.swing.JComponent; import javax.swing.JFrame; import javax.swing.JLabel; import javax.swing.JMenu; import javax.swing.JMenuBar; import javax.swing.JMenuItem; import javax.swing.JPanel; import javax.swing.JRadioButton; import javax.swing.KeyStroke; import javax.swing.LayoutFocusTraversalPolicy; import javax.swing.SwingUtilities; import javax.swing.border.TitledBorder; /**  * This is a JPanel subclass which provides a special functionality  * for its children buttons components.  * It makes it possible to transfer focus from button to button  * with help of arrows keys.  * <p>The following example shows how to enable cyclic focus transfer   * <pre>  * import org.jdesktop.swinghelper.buttonpanel.*;   * import javax.swing.*;  *  * public class SimpleDemo {  *     public static void main(String[] args) throws Exception {  *         SwingUtilities.invokeLater(new Runnable() {  *             public void run() {  *                 final JFrame frame = new JFrame();  *                 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  *         *                 JXButtonPanel panel = new JXButtonPanel();  *                 panel.setCyclic(true);  *         *                 panel.add(new JButton("One"));  *                 panel.add(new JButton("Two"));  *                 panel.add(new JButton("Three"));  *         *                 frame.add(panel);  *                 frame.setSize(200, 200);  *                 frame.setLocationRelativeTo(null);  *                 frame.setVisible(true);  *             }  *         });  *     }  * }  * </pre>   *    * If your buttons inside JXButtonPanel are added to one ButtonGroup  * arrow keys will transfer selection between them as well as they do it for focus<p>  * Note: you can control this behaviour with setGroupSelectionFollowFocus(boolean)   * <pre>  * import org.jdesktop.swinghelper.buttonpanel.*;  * import javax.swing.*;  *  * public class RadioButtonDemo {  *     public static void main(String[] args) throws Exception {  *         SwingUtilities.invokeLater(new Runnable() {  *             public void run() {  *                 final JFrame frame = new JFrame();  *                 frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);  *   *                 JXButtonPanel panel = new JXButtonPanel();  *                 ButtonGroup group = new ButtonGroup();  *   *                 JRadioButton rb1 = new JRadioButton("One");  *                 panel.add(rb1);  *                 group.add(rb1);  *                 JRadioButton rb2 = new JRadioButton("Two");  *                 panel.add(rb2);  *                 group.add(rb2);  *                 JRadioButton rb3 = new JRadioButton("Three");  *                 panel.add(rb3);  *                 group.add(rb3);  *   *                 rb1.setSelected(true);  *                 frame.add(panel);  *   *                 frame.setSize(200, 200);  *                 frame.setLocationRelativeTo(null);  *                 frame.setVisible(true);  *             }  *         });  *     }  * }  * </pre>   *   * @author Alexander Potochkin  *   * https://swinghelper.dev.java.net/  * http://weblogs.java.net/blog/alexfromsun/   */ public class JXButtonPanel extends JPanel {     private boolean isCyclic;     private boolean isGroupSelectionFollowFocus;     /**      * {@inheritDoc}      */     public JXButtonPanel() {         super();         init();     }     /**      * {@inheritDoc}      */     public JXButtonPanel(LayoutManager layout) {         super(layout);         init();     }     /**      * {@inheritDoc}          */     public JXButtonPanel(boolean isDoubleBuffered) {         super(isDoubleBuffered);         init();     }     /**      * {@inheritDoc}      */     public JXButtonPanel(LayoutManager layout, boolean isDoubleBuffered) {         super(layout, isDoubleBuffered);         init();     }     private void init() {         setFocusTraversalPolicyProvider(true);         setFocusTraversalPolicy(new JXButtonPanelFocusTraversalPolicy());         ActionListener actionHandler = new ActionHandler();         registerKeyboardAction(actionHandler, ActionHandler.FORWARD,                 KeyStroke.getKeyStroke(KeyEvent.VK_RIGHT, 0),                 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);         registerKeyboardAction(actionHandler, ActionHandler.FORWARD,                 KeyStroke.getKeyStroke(KeyEvent.VK_DOWN, 0),                 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);         registerKeyboardAction(actionHandler, ActionHandler.BACKWARD,                 KeyStroke.getKeyStroke(KeyEvent.VK_LEFT, 0),                 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);         registerKeyboardAction(actionHandler, ActionHandler.BACKWARD,                 KeyStroke.getKeyStroke(KeyEvent.VK_UP, 0),                 JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);         setGroupSelectionFollowFocus(true);     }     /**      * Returns whether arrow keys should support      * cyclic focus traversal ordering for for this JXButtonPanel.         */     public boolean isCyclic() {         return isCyclic;     }     /**      * Sets whether arrow keys should support      * cyclic focus traversal ordering for this JXButtonPanel.      */     public void setCyclic(boolean isCyclic) {         this.isCyclic = isCyclic;     }     /**      * Returns whether arrow keys should transfer button's       * selection as well as focus for this JXButtonPanel.<p>      *       * Note: this property affects buttons which are added to a ButtonGroup       */     public boolean isGroupSelectionFollowFocus() {         return isGroupSelectionFollowFocus;     }     /**      * Sets whether arrow keys should transfer button's      * selection as well as focus for this JXButtonPanel.<p>      *       * Note: this property affects buttons which are added to a ButtonGroup       */     public void setGroupSelectionFollowFocus(boolean groupSelectionFollowFocus) {         isGroupSelectionFollowFocus = groupSelectionFollowFocus;     }     private static ButtonGroup getButtonGroup(AbstractButton button) {         ButtonModel model = button.getModel();         if (model instanceof DefaultButtonModel) {             return ((DefaultButtonModel) model).getGroup();         }         return null;     }     private class ActionHandler implements ActionListener {         private static final String FORWARD = "moveSelectionForward";         private static final String BACKWARD = "moveSelectionBackward";         public void actionPerformed(ActionEvent e) {             FocusTraversalPolicy ftp = JXButtonPanel.this.getFocusTraversalPolicy();             if (ftp instanceof JXButtonPanelFocusTraversalPolicy) {                 JXButtonPanelFocusTraversalPolicy xftp =                         (JXButtonPanelFocusTraversalPolicy) ftp;                 String actionCommand = e.getActionCommand();                 Component fo =                         KeyboardFocusManager.getCurrentKeyboardFocusManager().getFocusOwner();                 Component next;                 xftp.setAlternativeFocusMode(true);                 if (FORWARD.equals(actionCommand)) {                     next = xftp.getComponentAfter(JXButtonPanel.this, fo);                 } else if (BACKWARD.equals(actionCommand)) {                     next = xftp.getComponentBefore(JXButtonPanel.this, fo);                 } else {                     throw new AssertionError("Unexpected action command: " + actionCommand);                 }                 xftp.setAlternativeFocusMode(false);                 if (fo instanceof AbstractButton) {                     AbstractButton b = (AbstractButton) fo;                     b.getModel().setPressed(false);                 }                 if (next != null) {                     if (fo instanceof AbstractButton && next instanceof AbstractButton) {                         ButtonGroup group = getButtonGroup((AbstractButton) fo);                         AbstractButton nextButton = (AbstractButton) next;                         if (group != getButtonGroup(nextButton)) {                             return;                         }                         if (isGroupSelectionFollowFocus() && group != null &&                                  group.getSelection() != null && !nextButton.isSelected()) {                             nextButton.setSelected(true);                         }                         next.requestFocusInWindow();                     }                 }             }         }     }     private class JXButtonPanelFocusTraversalPolicy extends LayoutFocusTraversalPolicy {         private boolean isAlternativeFocusMode;         public boolean isAlternativeFocusMode() {             return isAlternativeFocusMode;         }         public void setAlternativeFocusMode(boolean alternativeFocusMode) {             isAlternativeFocusMode = alternativeFocusMode;         }         protected boolean accept(Component c) {             if (!isAlternativeFocusMode() && c instanceof AbstractButton) {                 AbstractButton button = (AbstractButton) c;                 ButtonGroup group = JXButtonPanel.getButtonGroup(button);                 if (group != null && group.getSelection() != null                         && !button.isSelected()) {                     return false;                 }             }             return super.accept(c);         }         public Component getComponentAfter(Container aContainer, Component aComponent) {             Component componentAfter = super.getComponentAfter(aContainer, aComponent);             if (!isAlternativeFocusMode()) {                 return componentAfter;             }             if (JXButtonPanel.this.isCyclic()) {                 return componentAfter == null ?                         getFirstComponent(aContainer) : componentAfter;             }             if (aComponent == getLastComponent(aContainer)) {                 return aComponent;             }             return componentAfter;         }         public Component getComponentBefore(Container aContainer, Component aComponent) {             Component componentBefore = super.getComponentBefore(aContainer, aComponent);             if (!isAlternativeFocusMode()) {                 return componentBefore;             }             if (JXButtonPanel.this.isCyclic()) {                 return componentBefore == null ?                         getLastComponent(aContainer) : componentBefore;             }             if (aComponent == getFirstComponent(aContainer)) {                 return aComponent;             }             return componentBefore;         }     } } /**  * @author Alexander Potochkin  *   * https://swinghelper.dev.java.net/  * http://weblogs.java.net/blog/alexfromsun/   */ class JXButtonPanelDemo extends JFrame {     private ButtonGroup radioGroup = new ButtonGroup();     public JXButtonPanelDemo() {         super("JXButtonPanel demo");         setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);         setResizable(false);         JPanel topPanel = new JPanel(new GridLayout(1, 0));                  final JXButtonPanel radioGroupPanel = createRadioJXButtonPanel();         topPanel.add(radioGroupPanel);                  final JXButtonPanel checkBoxPanel = createCheckBoxJXButtonPanel();         topPanel.add(checkBoxPanel);         add(topPanel);         add(createButtonJXButtonPanel(), BorderLayout.SOUTH);         pack();         JMenuBar bar = new JMenuBar();         JMenu menu = new JMenu("Options");         JMenuItem item = new JMenuItem("Unselect radioButtons");         item.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_C, InputEvent.ALT_MASK));         item.addActionListener(new ActionListener() {             public void actionPerformed(ActionEvent e) {                 // hack for 1.5                  // in 1.6 ButtonGroup.clearSelection added                 JRadioButton b = new JRadioButton();                 radioGroup.add(b);                 b.setSelected(true);                 radioGroup.remove(b);             }         });         menu.add(item);         bar.add(menu);         setJMenuBar(bar);         setSize(300, 300);         setLocationRelativeTo(null);     }     private JXButtonPanel createRadioJXButtonPanel() {         JXButtonPanel panel = new JXButtonPanel();         panel.setLayout(new GridLayout(0, 1));         JRadioButton one = new JRadioButton("One");         panel.add(one);         radioGroup.add(one);         JRadioButton two = new JRadioButton("Two");         panel.add(two);         radioGroup.add(two);         JRadioButton three = new JRadioButton("Three");         panel.add(three);         radioGroup.add(three);         JRadioButton four = new JRadioButton("Four");         panel.add(four);         radioGroup.add(four);         one.setSelected(true);         panel.setBorder(BorderFactory.createTitledBorder("JXButtonPanel"));         return panel;     }     private JXButtonPanel createCheckBoxJXButtonPanel() {         JXButtonPanel panel = new JXButtonPanel();         panel.setLayout(new GridLayout(0, 1));         JCheckBox one = new JCheckBox("One");         panel.add(one);         JCheckBox two = new JCheckBox("Two");         panel.add(two);         JCheckBox three = new JCheckBox("Three");         panel.add(three);         JCheckBox four = new JCheckBox("Four");         panel.add(four);         panel.setBorder(BorderFactory.createTitledBorder("JXButtonPanel"));         return panel;     }     private JPanel createButtonJXButtonPanel() {         JPanel ret = new JPanel(new BorderLayout());         JLabel label = new JLabel("Does JXButtonPanel support arrow keys ?");         label.setBorder(BorderFactory.createEmptyBorder(0, 0, 10, 0));         JPanel temp = new JPanel();         temp.add(label);         ret.add(temp);                  JXButtonPanel panel = new JXButtonPanel();         panel.setCyclic(true);         panel.add(new JButton("Yes"));         panel.add(new JButton("Sure"));         panel.add(new JButton("Absolutely !"));         panel.setBorder(BorderFactory.createTitledBorder(null,                  "JXButtonPanel.setCyclic(true)",                 TitledBorder.CENTER, TitledBorder.BOTTOM));         ret.setBorder(BorderFactory.createEmptyBorder(10, 0, 10, 0));         ret.add(panel, BorderLayout.SOUTH);         return ret;     }     public static void main(String[] args) throws Exception {         SwingUtilities.invokeLater(new Runnable() {             public void run() {                 new JXButtonPanelDemo().setVisible(true);             }         });              } }