![](https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg4D_r5nw-cNrJSvytU_CBd47powAX7jJFRLd7kc7S_d85XV5C7qRZkFWRG_eTHcL2aTPGlN_VhiUUSlGxkMB0OSH4hfTDjd3jbRhwPyvQ8xh8V5dBcBIu1US3a4T_eMcHPm9qc2ef6azw/s400/fifteenpieces.png)
Devil in the Details
There are a few aesthetic issues with using JRadioButtons: should they be arranged horizontally or vertically; should they be horizontal up to a certain number of items, then switch to vertical; should they have a choice at the top for 'null'; should you be able to 'unselect all' after you've made an initial choice; should they only be used for not-nullable fields; etc. These are the kind of things keeping me from putting JRadioButtons in the core SwingWidgetBuilder.
But it's straightforward to add your own WidgetBuilder - where you can decide all the above little UI aesthetics according to your personal taste.
In a Bind
While you're at it, you probably want to add binding support. Again this depends on your personal preference, but let's say you want to use BeansBindingProcessor. It turns out BeansBinding isn't very good at binding to groups of JRadioButtons (a known problem), so one approach is to dummy up a little ButtonGroupPanel with its own getter and setter.
Example Code
Here's an example WidgetBuilder. You'll need to add it as part of a CompositeWidgetBuilder, as shown here in the Reference Documentation.
public class JRadioButtonWidgetBuilder
implements WidgetBuilder<JComponent, SwingMetawidget>, SwingValuePropertyProvider {
public JComponent buildWidget( String elementName, Map<String, String> attributes, SwingMetawidget metawidget ) {
String lookupAttribute = attributes.get( LOOKUP );
if ( lookupAttribute == null ) {
return null;
}
String[] lookups = ArrayUtils.fromString( lookupAttribute );
String[] lookupLabels = ArrayUtils.fromString( attributes.get( LOOKUP_LABELS ) );
ButtonGroupPanel panel = new ButtonGroupPanel();
panel.setLayout( new GridLayout( 1, lookups.length ) );
for ( int loop = 0; loop < lookups.length; loop++ ) {
JRadioButton radioButton = new JRadioButton();
if ( lookupLabels.length == 0 ) {
radioButton.setText( lookups[loop] );
} else {
radioButton.setText( lookupLabels[loop] );
}
radioButton.setActionCommand( lookups[loop] );
panel.add( radioButton );
}
return panel;
}
public String getValueProperty( Component component ) {
if ( component instanceof ButtonGroupPanel ) {
return "selected";
}
return null;
}
public static class ButtonGroupPanel
extends JPanel {
private ButtonGroup mButtonGroup = new ButtonGroup();
public String getSelected() {
ButtonModel buttonModel = mButtonGroup.getSelection();
if ( buttonModel == null ) {
return null;
}
return buttonModel.getActionCommand();
}
public void setSelected( String selected ) {
for ( Enumeration<AbstractButton> e = mButtonGroup.getElements(); e.hasMoreElements(); ) {
AbstractButton button = e.nextElement();
if ( !selected.equals( button.getActionCommand() ) ) {
continue;
}
String oldValue = getSelected();
mButtonGroup.setSelected( button.getModel(), true );
firePropertyChange( "selected", oldValue, selected );
break;
}
}
@Override
protected void addImpl( Component component, Object constraints, int index ) {
super.addImpl( component, constraints, index );
if ( component instanceof AbstractButton ) {
mButtonGroup.add( (AbstractButton) component );
}
}
}
}
implements WidgetBuilder<JComponent, SwingMetawidget>, SwingValuePropertyProvider {
public JComponent buildWidget( String elementName, Map<String, String> attributes, SwingMetawidget metawidget ) {
String lookupAttribute = attributes.get( LOOKUP );
if ( lookupAttribute == null ) {
return null;
}
String[] lookups = ArrayUtils.fromString( lookupAttribute );
String[] lookupLabels = ArrayUtils.fromString( attributes.get( LOOKUP_LABELS ) );
ButtonGroupPanel panel = new ButtonGroupPanel();
panel.setLayout( new GridLayout( 1, lookups.length ) );
for ( int loop = 0; loop < lookups.length; loop++ ) {
JRadioButton radioButton = new JRadioButton();
if ( lookupLabels.length == 0 ) {
radioButton.setText( lookups[loop] );
} else {
radioButton.setText( lookupLabels[loop] );
}
radioButton.setActionCommand( lookups[loop] );
panel.add( radioButton );
}
return panel;
}
public String getValueProperty( Component component ) {
if ( component instanceof ButtonGroupPanel ) {
return "selected";
}
return null;
}
public static class ButtonGroupPanel
extends JPanel {
private ButtonGroup mButtonGroup = new ButtonGroup();
public String getSelected() {
ButtonModel buttonModel = mButtonGroup.getSelection();
if ( buttonModel == null ) {
return null;
}
return buttonModel.getActionCommand();
}
public void setSelected( String selected ) {
for ( Enumeration<AbstractButton> e = mButtonGroup.getElements(); e.hasMoreElements(); ) {
AbstractButton button = e.nextElement();
if ( !selected.equals( button.getActionCommand() ) ) {
continue;
}
String oldValue = getSelected();
mButtonGroup.setSelected( button.getModel(), true );
firePropertyChange( "selected", oldValue, selected );
break;
}
}
@Override
protected void addImpl( Component component, Object constraints, int index ) {
super.addImpl( component, constraints, index );
if ( component instanceof AbstractButton ) {
mButtonGroup.add( (AbstractButton) component );
}
}
}
}
Feedback welcome!
2 comments:
Hi Richard,
Could you provide some guidance on how using a radiobutton group might be achieved via JSF2 ?
Thanks
Andrew
Andrew,
JSF already has a component (HtmlSelectOneRadio) that manages radiobutton groups for you.
To tell Metawidget to use it, you just need to add a little custom WidgetBuilder to suit your needs. Or, as a quick hack, you can do...
@UiFacesComponent( "javax.faces.HtmlSelectManyCheckbox" )
...on your getter.
Regards,
Richard.
Post a Comment