How to get/set JRadionButtonMenuItem dynamically?

614 views Asked by At

This example has Radio Buttons located on a Sub Menu as seen here.

enter image description here

What I would like to do is anytime the "Change Radio Button" button is pressed, it will change which button is selected on the menu. This means it has to first retrieve which is currently set then select the other.

Granted for this simple sample the Radio Buttons could be made instance variables to make things easy but image the JMenu and associated sub-menus and radio buttons are generated is some class further down in the bowels of the program. Direct access is not that direct.

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;

public class RadioButtonsOnMenu 
{
    public static void main(final String args[]) 
    {
        JFrame frame = new JFrame("MenuSample Example");
        JButton jButton = new JButton("Change Radio Button");
        jButton.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent arg0) {
                System.out.println("Changing Radion Button");
                //How to change the JButton on the menu?
                //frame.getMenuBar().......
            }
        });

        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        JPanel jPanel = new JPanel();
        jPanel.add(jButton);
        
        frame.add(jPanel);
        frame.setJMenuBar(buildMenu());
        frame.setSize(350, 250);
        frame.setVisible(true);
    }
    
    public static JMenuBar buildMenu()
    {
        JMenuBar menuBar = new JMenuBar();
        JMenu fileMenu = new JMenu("File");
        fileMenu.setMnemonic(KeyEvent.VK_F);
        menuBar.add(fileMenu);

        JMenuItem newMenuItem = new JMenuItem("New", KeyEvent.VK_N);
        fileMenu.add(newMenuItem);

        JMenu findOptionsMenu = new JMenu("Options");
        findOptionsMenu.setMnemonic(KeyEvent.VK_O);
        fileMenu.add(findOptionsMenu);

        ButtonGroup directionGroup = new ButtonGroup();
        
        JRadioButtonMenuItem forwardMenuItem = new JRadioButtonMenuItem("Forward", true);
        forwardMenuItem.setMnemonic(KeyEvent.VK_F);
        findOptionsMenu.add(forwardMenuItem);
        directionGroup.add(forwardMenuItem);

        JRadioButtonMenuItem backwardMenuItem = new JRadioButtonMenuItem("Backward");
        backwardMenuItem.setMnemonic(KeyEvent.VK_B);
        findOptionsMenu.add(backwardMenuItem);
        directionGroup.add(backwardMenuItem);
        
        return menuBar;
    }
}

It is not clear how best to access the sub-menu and associated radio button settings within the JButton action.

        jButton.addActionListener(new ActionListener(){
            public void actionPerformed(ActionEvent arg0) {
                System.out.println("Changing Radion Button");
                //How to change the JButton on the menu?
                //frame.getMenuBar().......
            }
        });

I could probably get the Menu Bar from the Frame and drill down figure the code can get messy if there Menu Bar has numerous items, sub items and even multiple radio button groups.

Is there a more direct way to find out which Radio Buttons on the menu are selected as well as a more direct way to change their value?

4

There are 4 answers

2
Gilbert Le Blanc On BEST ANSWER

The "trick" is to create an application model to hold the value of the menu radio buttons.

Here's the GUI I created.

MenuSample Example

I started the Swing application with a call to the SwingUtilities invokeLater method. This method ensures that the Swing components are created and executed on the Event Dispatch Thread.

I created a JFrame and a JButton JPanel. I separated the creation of the JFrame and JPanel.

I created an application model class to hold a boolean which determines whether forward or backward is selected. The JButton ActionListener switches the state of the boolean. The updateRadioButtonMenu method updates the selected state of the radio button menu items.

Here's the complete runnable code.

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.KeyEvent;

import javax.swing.BorderFactory;
import javax.swing.ButtonGroup;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JMenuItem;
import javax.swing.JPanel;
import javax.swing.JRadioButtonMenuItem;
import javax.swing.SwingUtilities;

public class RadioButtonsOnMenu implements Runnable {

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new RadioButtonsOnMenu());
    }
    
    private ApplicationModel model;
    
    private JRadioButtonMenuItem backwardMenuItem;
    private JRadioButtonMenuItem forwardMenuItem;
    
    public RadioButtonsOnMenu() {
        this.model = new ApplicationModel();
    }

    @Override
    public void run() {
        JFrame frame = new JFrame("MenuSample Example");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setJMenuBar(createMenuBar());

        frame.add(createButtonPanel());
        
        frame.pack();
        frame.setLocationByPlatform(true);
        frame.setVisible(true);
    }
    
    private JMenuBar createMenuBar() {
        JMenuBar menuBar = new JMenuBar();
        JMenu fileMenu = new JMenu("File");
        fileMenu.setMnemonic(KeyEvent.VK_F);
        menuBar.add(fileMenu);

        JMenuItem newMenuItem = new JMenuItem("New", KeyEvent.VK_N);
        fileMenu.add(newMenuItem);

        JMenu findOptionsMenu = new JMenu("Options");
        findOptionsMenu.setMnemonic(KeyEvent.VK_O);
        fileMenu.add(findOptionsMenu);

        ButtonGroup directionGroup = new ButtonGroup();

        forwardMenuItem = new JRadioButtonMenuItem("Forward", model.isForward());
        forwardMenuItem.setMnemonic(KeyEvent.VK_F);
        findOptionsMenu.add(forwardMenuItem);
        directionGroup.add(forwardMenuItem);

        backwardMenuItem = new JRadioButtonMenuItem("Backward", !model.isForward());
        backwardMenuItem.setMnemonic(KeyEvent.VK_B);
        findOptionsMenu.add(backwardMenuItem);
        directionGroup.add(backwardMenuItem);

        return menuBar;
    }
    
    private JPanel createButtonPanel() {
        JPanel panel = new JPanel();
        panel.setBorder(BorderFactory.createEmptyBorder(100, 100, 100, 100));
        
        JButton button = new JButton("Change Radio Button");
        button.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent event) {
                model.setForward(!model.isForward());
                updateRadioButtonMenu();
            }
        });
        panel.add(button);
        
        return panel;
    }
    
    public void updateRadioButtonMenu() {
        forwardMenuItem.setSelected(model.isForward());
        backwardMenuItem.setSelected(!model.isForward());
    }
    
    public class ApplicationModel {
        
        private boolean isForward;
        
        public ApplicationModel() {
            this.isForward = true;
        }

        public boolean isForward() {
            return isForward;
        }

        public void setForward(boolean isForward) {
            this.isForward = isForward;
        }
        
    }

}
0
David On

What you could do is to save the state in a boolean. You could add listener to the radio buttons and change the boolean everytime one of them is selected

boolean isForward = true;

so when changed to backward you set the value to false. This way you don't need to get The state of the radiobuttons everytime. In your button actionlistener you could then do:

jButton.addActionListener(new ActionListener(){
    public void actionPerformed(ActionEvent arg0) {
        System.out.println("Changing Radion Button");

            forwardRadioButton.setState(!isForward);
            backwardRadioButton.setState(isForward);
            iSForward = !isForward;
     }
});
1
The Blind Hawk On

I would say you need to do these two things:

Since you seem to have a lot of items it is best to store them somewhere else

1 Create a class to store all the items and then just pass the class

public class myItemHolder{
    //declare all the items here instead of at the main
    JButton jButton = new JButton("Change Radio Button");
    ButtonGroup directionGroup = new ButtonGroup();
    JRadioButtonMenuItem forwardMenuItem = new JRadioButtonMenuItem("Forward", true);
    JRadioButtonMenuItem backwardMenuItem = new JRadioButtonMenuItem("Backward");
    
    myListener(myItemHolder items){
        directionGroup.add(forwardMenuItem);
    }
    public ButtonGroup getButtons() {
        return directionGroup;
    }
    public JButton getClick() {
        return jButton;
    }
}

2 Create your own action listener class like so

public class myListener implements ActionListener{
    myItemHolders items;
    myListener(myItemHolder items){
        this.items=items; 
    }
    @Override
    public void actionPerformed(ActionEvent e) {
        //get the radiobutton like so and do what you want with it
        items.getButtons()
    }
}

Now you just need to do this in the main:

public class RadioButtonsOnMenu 
{
    public static void main(final String args[]) 
    {
        myItemHolder items = new myItemHolder();
        items.getClick.addActionListener(new myListener(items));
    }
}

And there you can access everything easily :)
It is all a matter of where you declare your stuff.
Or if you only want to send the ButtonGroup you can just do so by changing the structure a little so the actionlistener only requests the ButtonGroup and give it items.getButtons() instead of items.

1
Tim Hunter On

Here's another possible way to go about it using Enum state tracking. I make use of a Enum and a Map to track the Radio Button that should be activated. This lets it scale as large as you want for associated Radio Button items within the same JMenu.

RadioMenu

package tools;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.HashMap;

import javax.swing.JMenu;
import javax.swing.JRadioButtonMenuItem;

public class RadioMenu<E extends Enum<E>> extends JMenu {
  private static final long serialVersionUID = 1L;
  
  private E currentState;
  private JRadioButtonMenuItem selectedRadioButton;
  
  private HashMap<E, JRadioButtonMenuItem> stateMap;
  
  public RadioMenu() {
    stateMap = new HashMap<E, JRadioButtonMenuItem>();
  }
  
  public RadioMenu(String name) {
    super(name);
    stateMap = new HashMap<E, JRadioButtonMenuItem>();
  }
  
  public void addRadioButton(E associatedState, JRadioButtonMenuItem radioButton) {
    //Set default to first added button
    if(stateMap.isEmpty()) {
      currentState = associatedState;
      radioButton.setSelected(true);
      selectedRadioButton = radioButton;
    }
    
    add(radioButton);
    stateMap.put(associatedState, radioButton);
    radioButton.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        setState(associatedState);
      }
    });
  }
  
  public void generateButtonsFromEnum(Class<E> enumType) {
    for(E enumValue : enumType.getEnumConstants()) {
      addRadioButton(enumValue, new JRadioButtonMenuItem(enumValue.toString()));
    }
  }
  
  public E getState() {
    return currentState;
  }
  
  public void setState(E newState) {
    currentState = newState;
    selectedRadioButton.setSelected(false);
    
    selectedRadioButton = stateMap.get(newState);
    selectedRadioButton.setSelected(true);
  }
}

RadioMenuTest

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JMenu;
import javax.swing.JMenuBar;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;

import tools.RadioMenu;

public class RadioMenuTest implements Runnable {

  public enum RadioOptions {
    Forward, Backward, Left, Right
  }
  
  public static void main(String[] args) {
    SwingUtilities.invokeLater(new RadioMenuTest());
  }
  
  private RadioMenu<RadioOptions> optionsMenu;
  
  @Override
  public void run() {
    JFrame frame = new JFrame("RadioMenu Test");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
    frame.setJMenuBar(createMenuBar());
    frame.getContentPane().add(createButtonPanel());
    
    frame.pack();
    frame.setLocationByPlatform(true);
    frame.setVisible(true);
  }

  private JMenuBar createMenuBar() {
    JMenuBar menuBar = new JMenuBar();
    JMenu fileMenu = new JMenu("File");
    menuBar.add(fileMenu);
    
    optionsMenu = new RadioMenu<RadioOptions>("Options");
    optionsMenu.generateButtonsFromEnum(RadioOptions.class);
    
    fileMenu.add(optionsMenu);
    
    return menuBar;
  }
  
  private JPanel createButtonPanel() {
    JPanel panel = new JPanel(new FlowLayout());
    
    JButton setBackwardButton = new JButton("Set To Backward");
    setBackwardButton.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        optionsMenu.setState(RadioOptions.Backward);
      }
    });
    panel.add(setBackwardButton);
    
    JButton setRightButton = new JButton("Set To Right");
    setRightButton.addActionListener(new ActionListener() {
      @Override
      public void actionPerformed(ActionEvent e) {
        optionsMenu.setState(RadioOptions.Right);
      }
    });
    panel.add(setRightButton);
    
    return panel;
  }
}