Toggle 接口源码全景解析:可切换控件的统一契约
如果说ToggleGroup是“管理者”,那么Toggle就是“被管理者”。这个接口定义了所有可切换控件(如RadioButton、CheckBox、ToggleButton)必须遵守的统一契约,使得ToggleGroup能够以多态的方式管理它们,而无需关心具体控件的实现细节。
一、Toggle接口在 JavaFX 全局架构中的定位
| 维度 | 定位 |
|---|---|
| 层级 | javafx.scene.control包,属于UI 控件层的接口定义。 |
| 设计模式 | 策略模式+观察者模式:定义可切换行为的策略,并利用属性(Property)实现可观察状态。 |
| 与属性框架的关系 | 直接依赖于BooleanProperty(selected)和ObjectProperty(toggleGroup),将状态和行为全部通过属性暴露,实现与 UI 框架的无缝集成。 |
| MVVM 角色 | 可视为View 层控件的抽象模型:封装了“选中状态”和“所属分组”这两个核心业务属性,并提供扩展数据存储(properties/userData)。 |
二、接口方法逐一剖析(融合历史知识)
1. 分组管理:toggleGroupProperty()及 getter/setter
ObjectProperty<ToggleGroup>toggleGroupProperty();ToggleGroupgetToggleGroup();voidsetToggleGroup(ToggleGrouptoggleGroup);ObjectProperty<ToggleGroup>:这是我们之前深入剖析过的ObjectProperty(继承自Property<T>、WritableValue<T>、ReadOnlyProperty<T>)。它具备:- 可观察性:外界可以添加
ChangeListener或InvalidationListener监听分组变化。 - 可写性:允许
ToggleGroup内部通过setToggleGroup(this)来建立双向关联。 - 身份信息:
getBean()返回所属Toggle实例,getName()通常为"toggleGroup",便于调试和框架内省。
- 可观察性:外界可以添加
getToggleGroup()/setToggleGroup():是属性访问的便捷包装,实际委托给toggleGroupProperty().get()和toggleGroupProperty().set(...)。
设计意图:通过属性暴露分组引用,使得ToggleGroup可以利用属性绑定机制(如bind())或监听机制来与Toggle同步,无需手动维护回调列表。
2. 选中状态管理:selectedProperty()及 getter/setter
BooleanPropertyselectedProperty();booleanisSelected();voidsetSelected(booleanselected);BooleanProperty:这是BooleanProperty的实例(继承自Property<Boolean>、WritableValue<Boolean>、ReadOnlyProperty<Boolean>),同样具备可观察、可写、身份信息。isSelected()/setSelected():直接操作底层BooleanProperty。
关键点:
selectedProperty()是BooleanProperty而非ReadOnlyBooleanProperty,意味着外界可以直接调用set(true)。但这并不意味着控件可以被任意修改——因为ToggleGroup在管理时会检查该属性是否被绑定(isBound()),并只在合适时机修改,从而保证互斥规则。- 该属性通常由具体控件(如
RadioButton)内部绑定到 UI 交互事件(如鼠标点击),同时允许ToggleGroup通过代码修改。
3. 扩展数据存储:getProperties()、getUserData()、setUserData()
ObservableMap<Object,Object>getProperties();ObjectgetUserData();voidsetUserData(Objectvalue);ObservableMap:直接继承自Observable,因此 map 的变更(增删改)也会发出失效通知。这为Toggle提供了动态扩展属性的能力,与Node的getProperties()完全一致。getUserData()/setUserData():是对getProperties().put(USER_DATA_KEY, value)的便捷封装。USER_DATA_KEY是内部静态Object标记,保证唯一性。
设计价值:使得Toggle可以携带任意业务数据(如关联的对象 ID、额外状态),而无需通过继承子类扩展。这体现了 JavaFX“组合优于继承”和“开闭原则”。
三、与整个属性框架的历史类协作全景
| 底层组件 | 在Toggle中的使用方式 | 作用 |
|---|---|---|
Observable | BooleanProperty、ObjectProperty、ObservableMap都实现它 | 状态变化时能触发失效/变更事件。 |
ObservableValue<T> | 属性能被监听 | 外界可监听选中或分组变化。 |
WritableValue<T> | 属性可写 | ToggleGroup或控件自身可修改状态。 |
ReadOnlyProperty<T> | 属性带有getBean()/getName() | 提供身份信息,便于调试和框架内省。 |
Property<T> | 属性支持bind/unbind | 允许将selected或toggleGroup与其他属性绑定(但实际很少使用)。 |
BooleanProperty | 直接使用 | 存储selected状态。 |
ObjectProperty<ToggleGroup> | 直接使用 | 存储所属分组。 |
ObservableMap<K,V> | 提供getProperties() | 动态扩展数据。 |
BooleanBinding/ObjectBinding | 可选使用 | 可通过selectedProperty()创建绑定,与其他 UI 状态联动。 |
四、与ToggleGroup的协作机制(双向同步)
Toggle接口通过属性暴露的状态,与ToggleGroup形成双向绑定式协作:
组 → 单个 Toggle:
ToggleGroup在selectToggle(newToggle)中调用newToggle.setSelected(true)。- 如果旧
Toggle仍属于本组,则