Hi guys, I run into a problem. I am trying to write a small program. There should be 4 radio buttons and each of them controls the colour of the Content Pane.
The problem I have is with the anonymous inner class (I hear JamesCherrill muttering "why do you bother?", but hey!) and essentially I don't know how to attach the handlers - because I need to have multiple
radio buttons. If I didn't use the anonymous class I would do this:

redButton.addItemListener(new RadioButtonHandler(Color.RED));
blueButton.addItemListener(new RadioButtonHandler(Color.BLUE));
greenButton.addItemListener(new RadioButtonHandler(Color.GREEN));
magentaButton.addItemListener(new RadioButtonHandler(Color.MAGENTA));

but how do I do that with an anonymous class?
Is this allowed:

redButton.addItemListener(
    new ItemListener(
        ...
    )
)

blueButton.addItemListener(
    new ItemListener(
        ...
    )
)
greenButton.addItemListener(
    new ItemListener(
        ...
    )
)

magentaButton.addItemListener(
    new ItemListener(
        ...
    )
)

I am not sure if I can do that, so for now I only have a basic version if you like:

/*ColorChange.java*/
import java.awt.FlowLayout;
import java.awt.Color;
import javax.swing.JFrame;
import java.awt.event.ItemListener;
import java.awt.event.ItemEvent;
import javax.swing.JRadioButton;
import javax.swing.ButtonGroup;

public class ColorChange extends JFrame{
    private JRadioButton redButton;
    private JRadioButton blueButton;
    private JRadioButton greenButton;
    private JRadioButton magentaButton;
    private ButtonGroup radioGroup; 
//use example of font
    public ColorChange(){   
        super("colours test");
        setlayout( new FlowLayout());
        //radio buttons
        redButton = new JRadioButton( "Red", true );
        blueButton = new JRadioButton( "Blue", false );
        greenButton = new JRadioButton( "Green", false );
        magentaButton = new JRadioButton( "Magenta", false );
        add( redButton );
        add( blueButton );
        add( greenButton );
        add( magentaButton );

        radioGroup = new ButtonGroup();
        radioGroup.add( redButton );
        radioGroup.add( blueButton );
        radioGroup.add( greenButton );
        radioGroup.add( magentaButton );
    }//end of constructor

}//end of class

Cheers

This is a case where your first solution is good, and anonymous inner classes don't help.
You could attach the color as an attribute of each radio button
With Java 8 you just create a method rather than a class eg

void changeColor(ItemEvent e, Color c) {...

then use lambdas for the listeners:

redButton.addItemListener((e) -> changeColor(e, Color.RED));

As yet another alternative you could subclass JRadioButton, add a Color to its constructor, and add a suitable listener in the constructor...

Edited 2 Years Ago by JamesCherrill

thanks, I knew you would have mentioned java 8 lol! I will give a go to the first solution, and post back :-), I am sure I will get stuck again.
Funny though, I thought that in java 7 anonymous classes were heavily used, so I am surprised to hear that an inner class can't be easily implemented for such an easy taks!

An inner class yes. But because you want to pass a Color to the constructor to make different instances for each button, it can't be anonymous.

  • only one JRadioButton can firing SELECTED event in the case that they are added ButtonGroup

  • (something that make me some sence) use JRadioButtons with ItemListener without limitation came from ButtonGroup, or add JRadioButtons to ButtonGroup listened by ActionListener

  • (hightlevel) is possible, you can play with AbstractButton, better with ButtonModel directly and its events implemented in APIs without bothering with ItemListener/ActionListener (advantage of JButtons Components)

  • note there is an bug in AbstractButtons events, from Java1.6_xxx???, this is both ways bug from/to JToggleButtons Components (JToggle/JCheckbox/JRadioButton) to Swing GUI (dont remember that corectly, too lazy create a new trace in BugParade, etc)

Edited 2 Years Ago by mKorbel

OK, got that to work in the end, here is the source code in case - I doubt it :-) - any newbie like me wants to play around with it:

/*ColorChange.java*/
import java.awt.FlowLayout;
import java.awt.Color;
import javax.swing.JFrame;
import java.awt.event.ItemListener;
import java.awt.event.ItemEvent;
import javax.swing.JRadioButton;
import javax.swing.ButtonGroup;

public class ColorChange extends JFrame{
    //declare button variables
    private JRadioButton redButton;
    private JRadioButton blueButton;
    private JRadioButton greenButton;
    private JRadioButton magentaButton;
    private ButtonGroup radioGroup; 
//use example of font
    public ColorChange(){   
        super("colours test");
        setLayout( new FlowLayout());//set layout
        //radio buttons
        redButton = new JRadioButton( "Red", true );
        blueButton = new JRadioButton( "Blue", false );
        greenButton = new JRadioButton( "Green", false );
        magentaButton = new JRadioButton( "Magenta", false );
        //add to JFrame
        add( redButton );
        add( blueButton );
        add( greenButton );
        add( magentaButton );
        //add to the buttongroup
        radioGroup = new ButtonGroup();
        radioGroup.add( redButton );
        radioGroup.add( blueButton );
        radioGroup.add( greenButton );
        radioGroup.add( magentaButton );
        //register events
        redButton.addItemListener(new RadioButtonHandler(Color.RED));
        blueButton.addItemListener(new RadioButtonHandler(Color.BLUE));
        greenButton.addItemListener(new RadioButtonHandler(Color.GREEN));
        magentaButton.addItemListener(new RadioButtonHandler(Color.MAGENTA));
        //set the initial red colour
        getContentPane().setBackground( Color.RED );
    }//end of constructor

    //handling events
    private class RadioButtonHandler implements ItemListener{
        private Color colour;

        public RadioButtonHandler( Color targetColour){//constructor taking a color object
            colour = targetColour;
        }//end of constructor

        public void itemStateChanged( ItemEvent event ){
            getContentPane().setBackground( colour );
        }//end of method

    }//end of inner class

}//end of class



/*ColorChangeTest.java*/
import javax.swing.JFrame;
import java.awt.Dimension;
public class ColorChangeTest{
    public static void main( String[] args ){
        ColorChange colorChange = new ColorChange();
        colorChange.setDefaultCloseOperation( JFrame.EXIT_ON_CLOSE );
        colorChange.setVisible( true );
        Dimension minimumSize = new Dimension( 400, 200 );
        colorChange.setMinimumSize( minimumSize );
        colorChange.pack();
    }//end of main
}//end of class

Here is a pastebin, 2 files included:
http://pastebin.com/uCvkakBQ

Beware of itemListener. You get two events, one for the previous button being de-selected and one for the new button being selected. Your code works becuase you receive those two events in that order, but AFAIK there's no guarantee of that, so you should either
1) check the event to make sure its the right one or
2) use an action listener

Hi thanks for your feedback. I had no idea the issue existed, the textbook hasn't mentioned it - maybe it will at some point.

1) check the event to make sure its the right one or

how would I check the event? Is it just a matter of identifying which one is selected with perhaps isSelected()

2) use an action listener

Is it just a matter of replacing ItemListener with actionListener, so implementing the itemListener interface and passing the itemEvent?

You can query the ItemEvent with getStateChange(), which returns ItemEvent.SELECTED or ItemEvent.DESELECTED

If you use an ActionEvent it's just the same as responding to a click in an ordinary button - the ActionListener has an actionPerformed method that will be called when the radio button is clicked (ie turned on)

Edited 2 Years Ago by JamesCherrill

um, so something like this essentially (first solution)

public void itemStateChanged( ItemEvent event ){
            if(event.getStateChange() == ItemEvent.SELECTED ){
                getContentPane().setBackground( colour );
            }
        }//end of method

OK cool, I tried with the above test and it seems OK :-), thanks for bringing the issue up! New code is here:
http://pastebin.com/E0T3BXi4
ActionEvent solution...you will most often see in ordinary use.
I guess the author then used it just to demonstrate the ItemEvent

Edited 2 Years Ago by Violet_82

Hold on, sorry just noticed, shouldn't I use event if(event.getStateChange() == event.SELECTED ){ rather than ItemEvent if(event.getStateChange() == ItemEvent.SELECTED ){?

Edited 2 Years Ago by Violet_82

SELECTED is a public static variable in the ItemEvent class, so the second version is preferred. (You can access static members fromn an instance, but it's considered bad practice)

This article has been dead for over six months. Start a new discussion instead.