Radio Button enhancements for Action Framework (an apparent oversight)

6 views
Skip to first unread message

Mark Schmieder

unread,
Apr 1, 2023, 2:39:53 AM4/1/23
to ControlsFX
This is another grouped enhancement that I did a bit before the pandemic and refactored recently to reduce the amount of code overload required.

There was a likely unintentional oversight of covering Radio Buttons in the Action Framework, and this apparently hadn't been brought up before. I meant to contribute this work right before the pandemic, as I suspect I'm not alone in missing this one control type being absent from the framework.

There are several parts to implementing the support, and I was able to build it into my own fxguitoolkit after having previously only been able to take care of it by modifying parts of the Action Framework code in ControlsFX.

Nevertheless, it is probably better to borrow from what I did and enhance the original code base. Besides which, I have been in a bit of a dilemma about potential license conflict for derivational stuff, so I'd feel better releasing the code from my own library into ControlsFX (even if in an altered form) anyway.

Although there are hacky ways to do this, I built infrastructure to support it via enum categorization, and then wrote derived classes for stuff in ControlsFX in order to move away from rewrites of ControlsFX stuff whenever possible.

I will present first the simple code logic that allows for grabbing Radio Button Menu Items and Radio Button Controls via the Action Framework, as seen in my enhanced XActionUtilities class in fxguitoolkit. I will initially limit additional code references from that library in hopes that people can easily find it, or will wait for requests.

/**

* Takes the provided {@link XAction} and returns a {@link MenuItem}

* instance with all relevant properties bound to the properties of the

* Action.

* <p>

* NOTE: This is a revision of the method in ControlsFX ActionUtils, as

* we need to extend coverage for RadioMenuItem needs.

*

* @param action

* The {@link XAction} that the {@link MenuItem} should bind

* to.

* @return A {@link MenuItem} that is bound to the state of the provided

* {@link Action}

*/

public static MenuItem createMenuItem( final XAction action ) {

// NOTE: This is messy logic because we cannot yet use annotation alone

// in order to distinguish the required type of Menu Item to return.

// Preferably we would use a switch statement for the Action Verb cases.

final MenuItem menuItem = ( action.getClass().isAnnotationPresent( ActionCheck.class )

|| action.isCheck() || action.isToggle() )

? new CheckMenuItem()

: action.isChoice() ? new RadioMenuItem() : new MenuItem();


return configure( menuItem, action );

}


// NOTE: This is a revision of the method in ControlsFX ActionUtils, to

// extend coverage for RadioMenuItem needs.

private static < T extends MenuItem > T configure( final T menuItem, final Action action ) {

if ( action == null ) {

throw new NullPointerException( "Action cannot be null" ); //$NON-NLS-1$

}


// Button bind to action properties.

bindStyle( menuItem, action );


menuItem.textProperty().bind( action.textProperty() );

menuItem.disableProperty().bind( action.disabledProperty() );

menuItem.acceleratorProperty().bind( action.acceleratorProperty() );


// NOTE: This is the only setting unique to XAction and XActionGroup,

// but we can't make a nested call to ActionUtils.configure() as it is

// Private API, so we copy/paste and extend here instead.

if ( ( action instanceof XAction ) && ( ( XAction ) action ).isHideIfDisabled() ) {

menuItem.visibleProperty().bind( action.disabledProperty().not() );

}

else if ( ( action instanceof XActionGroup )

&& ( ( XActionGroup ) action ).isHideIfDisabled() ) {

menuItem.visibleProperty().bind( action.disabledProperty().not() );

}


menuItem.graphicProperty().bind( new ObjectBinding< Node >() {

{

bind( action.graphicProperty() );

}


@Override

protected Node computeValue() {

return copyNode( action.graphicProperty().get() );

}


@Override

public void removeListener( final InvalidationListener listener ) {

super.removeListener( listener );

unbind( action.graphicProperty() );

}

} );


// Add all the properties of the action into the button, and set up

// a listener so they are always copied across.

menuItem.getProperties().putAll( action.getProperties() );

action.getProperties()

.addListener( new MenuItemPropertiesMapChangeListener<>( menuItem, action ) );


// Handle the selected state of the menu item if it is a

// CheckMenuItem or RadioMenuItem.

if ( menuItem instanceof RadioMenuItem ) {

( ( RadioMenuItem ) menuItem ).selectedProperty()

.bindBidirectional( action.selectedProperty() );

}

else if ( menuItem instanceof CheckMenuItem ) {

( ( CheckMenuItem ) menuItem ).selectedProperty()

.bindBidirectional( action.selectedProperty() );

}


// Just call the execute method on the action itself when the action

// event occurs on the button.

menuItem.setOnAction( action );


return menuItem;

}


As it's hard to read discussions that follow code snippets, I'll tag a new comment for a brief summary of the other changes.

Mark Schmieder

unread,
Apr 1, 2023, 2:45:09 AM4/1/23
to ControlsFX
To summarize the additional changes I made to my enhanced Action Framework:

1. XAction class derives from ControlsFX Action and supports hiding if disabled, as well as ActionVerb enumeration (similar to ControlsFX sample code in DummyAction)
2. XActionGroup class derives from ControlsFX ActionGroup and identifies if it is a choice group as well as support for hiding if disabled
3. As noted above, ActionVerb enum added and individual queries present in XAction class to cut the verbiage of combined comparisons in XActionUtilities
4. Unrelated to the Radio Button support, a group of edits was made to XAxtionUtilities (from ActionUtils originals) to be conscious of ActionGroup vs. Action

As stated in the original post, all of this is in my GitHib fxguitoolkit project and can be viewed there, or make special requests for me to specifically curate additional example code snippets to post here for direct reference.

The differentiation between Action and ActionGroup in some behavioral aspects of the utility methods, should be a different pull request from the Radio Button support.
Reply all
Reply to author
Forward
0 new messages