Button of Choice: Use ToggleButtons as RadioButtons
For MQTT.fx I wanted to use ToggleButtons to e.g. choose the de coding of a MQTT Message or the QoS Level:
I found out that in context of a ToggleGroup ToggleButtons behave different than RadioButtons in terms of selection/deselection: unlike RadioButtons ToggleButtons can still be set to unselected state.
A RadioButton extends ToggleButton and overrides fire() (which is invoked when a user gesture indicates that an event for this ButtonBase
should occur aka “Button was clicked”):
RadioButton:
@Override public void fire() { // we don't toggle from selected to not selected if part of a group if (getToggleGroup() == null || !isSelected()) { super.fire(); } }
ToggleButton:
@Override public void fire() { setSelected(!isSelected()); fireEvent(new ActionEvent()); }
In a ToogleGroup ToggleButtons should behave like RadioButtons, so IMHO this is a bug worth a pull request for ToggleButton ��
One way to handle this is for sure to create a custom extension of ToggleButton implementing fire() in respect to the RadioButton.
But I like more to add behavior to existing controls.
This is my tweak to modify default behavior by adding filters to all ToogleButtons of a ToggleGroup consuming unwanted MouseEvents:
public class JavaFXUtil { private static JavaFXUtil me; private JavaFXUtil() { } public static JavaFXUtil get() { if (me == null) { me = new JavaFXUtil(); } return me; } public EventHandler<MouseEvent> consumeMouseEventfilter = (MouseEvent mouseEvent) -> { if (((Toggle) mouseEvent.getSource()).isSelected()) { mouseEvent.consume(); } }; public void addAlwaysOneSelectedSupport(final ToggleGroup toggleGroup) { toggleGroup.getToggles().addListener((Change<? extends Toggle> c) -> { while (c.next()) { for (final Toggle addedToggle : c.getAddedSubList()) { addConsumeMouseEventfilter(addedToggle); } } }); toggleGroup.getToggles().forEach(t -> { addConsumeMouseEventfilter(t); }); } private void addConsumeMouseEventfilter(Toggle toggle) { ((ToggleButton) toggle).addEventFilter(MouseEvent.MOUSE_PRESSED, consumeMouseEventfilter); ((ToggleButton) toggle).addEventFilter(MouseEvent.MOUSE_RELEASED, consumeMouseEventfilter); ((ToggleButton) toggle).addEventFilter(MouseEvent.MOUSE_CLICKED, consumeMouseEventfilter); } }
public class ButtonDemoController { @FXML private ToggleGroup g2; @FXML private ToggleGroup g3; public void initialize() { JavaFXUtil.get().addAlwaysOneSelectedSupport(g2); JavaFXUtil.get().addAlwaysOneSelectedSupport(g3); } }
Example code at GitHub.
Reference: | Button of Choice: Use ToggleButtons as RadioButtons from our JCG partner Jens Deters at the JavaFX Delight blog. |
I love toggle buttons just because they’re a break from the norm, but I think they might be confusing for people who aren’t familiar with them. And yes, of course I realize they’re totally intuitive and it’s fairly obvious how they work, but you know how it is…