Class ButtonGroup
RadioButtons so that exactly one is selected at a
time. Selecting a member deselects the previous one; when the user did the selecting
each radio's own onChange fires for both the leaving and the entering member and then
the group's onSelect fires with the new index, and when code did it none of the three
handlers runs -- the two members announce their VALUE to their watchers either way.
A group is not a widget, so it announces nothing of its own. It has no box, no
parent and no scene, so there is no node a watcher could attach its change to; the change
reaches the channel entire through the two members, which are widgets: the leaver's
VALUE and then the enterer's, both carrying the origin of whatever entered the swap,
and only then either member's handler. The whole swap settles before the first announcement,
because a half-swapped group is unreadable.
A group is one tab stop, not one per radio. Only the selected member (or the first
enabled one, before anything is selected) can take focus, and the arrow keys move the
selection and the focus together, wrapping at the ends and stepping over disabled members. That
is the Windows and GTK convention, it is what macOS Full Keyboard Access does inside a group,
and it is the pattern TabbedPane already uses for its headers. Without it a settings
form of six groups of four options costs twenty-four tab stops instead of six.
-
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionadd(RadioButton radio) Adds a radio to the group.Puts the group back in the state it had before anything was selected:selectedIndex()reports-1and the leaving member announcesVALUE/CODE; no handler runs, because a caller emptied the group.members()onSelect(@Nullable IntConsumer listener) The application's response to the user choosing a member: called with its index after a click, an arrow key or an assistive technology's select, once both members' own handlers have run.remove(RadioButton radio) Takes a radio out of the group for good: it is a radio on its own from then on.@Nullable RadioButtonselected()intsetSelectedIndex(int index) Selects the member atindex: a caller's write, so both members announceVALUE/CODEand no handler runs.
-
Constructor Details
-
ButtonGroup
public ButtonGroup()
-
-
Method Details
-
add
Adds a radio to the group. If it is already selected, it becomes the group's selection.Membership is what a screen reader speaks as "2 of 4", and adding a member changes that number for every member while painting nothing: the roving-focus pass only invalidates the tree when a focusable flag actually flips, and the first member's does not flip at all. So every member tells the tree itself, which costs nothing for a member not yet in a scene and is not per-frame work.
-
remove
Takes a radio out of the group for good: it is a radio on its own from then on. If it was the group's selection the group has none, and the radio stays selected. Nothing happens for a radio that is not a member. UI thread only.A radio leaves by itself, too, for as long as it is out of a scene it was in: taken out of the tree, or its window closed. The group does not hold it then, the others no longer count it in the "2 of 4" a screen reader speaks, and it takes its place again, among the members that are there, when it is back in a scene. A radio added to a group before it was ever in a scene is a member from the start.
- Parameters:
radio- the radio to take out- Returns:
- this group
-
onSelect
The application's response to the user choosing a member: called with its index after a click, an arrow key or an assistive technology's select, once both members' own handlers have run. Never forsetSelectedIndex(int),clearSelection()or a member'sRadioButton.select(), which are a caller's writes; to hear every change whatever caused it, watch the members.- Parameters:
listener- the handler, ornullto clear the slot- Returns:
- this group
- Throws:
IllegalStateException- if a handler is already registered
-
selectedIndex
public int selectedIndex()- Returns:
- the index of the selected radio, or -1 when none. A group is one of the two widgets
in this set that genuinely has no-selection as a state: it starts there, and
clearSelection()goes back
-
selected
- Returns:
- the selected radio, or null when none.
-
members
- Returns:
- an immutable view of the members, in the order they were added; one that is out of the scene it was in is not among them until it is back
-
setSelectedIndex
Selects the member atindex: a caller's write, so both members announceVALUE/CODEand no handler runs. Selecting the member that is already selected changes nothing and announces nothing. UI thread only.- Parameters:
index- a member in[0, memberCount), in the order they were added- Throws:
IndexOutOfBoundsException- ifindexis not a member; a group with no members has none, so every index throws there.-1is not the way to empty the group;clearSelection()is.
-
clearSelection
Puts the group back in the state it had before anything was selected:selectedIndex()reports-1and the leaving member announcesVALUE/CODE; no handler runs, because a caller emptied the group. No-op when nothing is selected. UI thread only.A radio group is one choice out of many and offers no way to un-choose from the keyboard or the mouse: this is the reset a form needs, and the only route back.
-