ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

ComboBox(1)

ComboBox(1) ComboBoxBase 源码深度解析:从属性框架到 UI 交互的桥梁ComboBoxBase是我们源码分析之旅中第一个真正的 UI 控件基类。在此之前,我们研究的都是Observable、Property、Binding、Toggle等抽象层面的东西。而ComboBoxBase是这些底层机制在具体用户界面组件中的首次大规模集成应用。它完全印证了我们之前得出的结论:JavaFX 的 UI 控件本质上就是一堆精心编排的Property,再加上一些事件处理和 CSS 伪类。理解了属性框架,就理解了 JavaFX 控件的骨架。一、ComboBoxBase在 JavaFX 全局架构中的定位维度定位层级javafx.scene.control包,继承自Control(而Control继承自Region,Region继承自Parent,最终继承自Node)。设计意图抽象基类,为所有“弹出式选择器”控件(如ComboBox、ColorPicker、DatePicker)提供统一的状态管理和交互契约。与属性框架的关系重度集成:value、editable、showing、armed全部通过属性暴露,ReadOnlyBooleanWrapper实现内部可写外部只读,ObjectPropertyBase管理事件处理器。设计模式模板方法模式:定义了show()/hide()的骨架,子类决定具体弹出内容;观察者模式:属性变化自动触发 CSS 伪类更新和可访问性通知。二、类注释剖析(Javadoc)“Abstract base class for ComboBox-like controls. … This base class makes no assumptions about what happens when theshow()andhide()methods are called”核心抽象:它不关心弹出的是下拉列表、颜色选择器还是日历,只关心“能弹出”和“能隐藏”这一行为本身。value属性:代表当前用户输入/选中的值,是整个控件的核心数据。editable属性:区分“只选”和“可输入”两种模式,子类据此决定是否显示文本框。分离目的:将ComboBox(下拉列表)与ColorPicker(颜色面板)等不同实现统一到同一个抽象层,避免代码重复。三、核心属性逐一剖析(融合历史知识)1.value—— 核心数据属性publicObjectPropertyTvalueProperty(){returnvalue;}privateObjectPropertyTvalue=newSimpleObjectProperty(this,"value");类型:ObjectPropertyT,这是我们熟悉的ObjectProperty,继承自PropertyT、WritableValueT、ReadOnlyPropertyT。作用:存储当前选中的值或用户输入的值。设计意义:外部可以通过bind()将value与业务模型双向绑定,实现自动同步。例如:comboBox.valueProperty().bindBidirectional(model.selectedItemProperty())。身份信息:构造时传入this和"value",使得getBean()返回ComboBoxBase实例,getName()返回"value",便于调试和框架内省。2.editable—— 可编辑状态(带伪类联动)publicBooleanPropertyeditableProperty(){returneditable;}privateBooleanPropertyeditable=newSimpleBooleanProperty(this,"editable",false){@Overrideprotectedvoidinvalidated(){pseudoClassStateChanged(PSEUDO_CLASS_EDITABLE,get());}};类型:BooleanProperty。核心亮点:重写invalidated()钩子。这是我们之前在ObjectPropertyBase中分析过的invalidated()方法的实战应用。工作机制:当editable属性变化时(无论是通过setEditable还是绑定),invalidated()被自动调用,进而更新 CSS 伪类:editable。这使得样式表可以根据editable状态自动调整 UI 外观(如文本框背景色变化)。设计价值:无需注册监听器,直接在属性内部自包含样式更新逻辑,简洁高效。3.showing—— 弹出状态(ReadOnlyBooleanWrapper经典应用)privateReadOnlyBooleanWrappershowing;publicReadOnlyBooleanPropertyshowingProperty(){returnshowingPropertyImpl().getReadOnlyProperty();}publicfinalbooleanisShowing(){returnshowingPropertyImpl().get();}privatevoidsetShowing(booleanvalue){Event.fireEvent(this,value?newEvent(ON_SHOWING):newEvent(ON_HIDING));showingPropertyImpl().set(value);Event.fireEvent(this,value?newEvent(ON_SHOWN):newEvent(ON_HIDDEN));}这是我们之前深入剖析的ReadOnlyObjectWrapper的孪生兄弟——ReadOnlyBooleanWrapper。内部可写:只有ComboBoxBase内部(或子类)可以调用setShowing()。外部只读:对外暴露ReadOnlyBooleanProperty,外界只能监听和读取。事件触发:在setShowing中,严格按照顺序触发四个事件:ON_SHOWING(弹出前)、ON_SHOWN(弹出后)、ON_HIDING(隐藏前)、ON_HIDDEN(隐藏后)。这允许开发者在这些关键时刻插入业务逻辑(如记录日志、加载数据)。伪类联动:在ReadOnlyBooleanWrapper的invalidated()中更新:showing伪类,使 CSS 能在弹出时改变控件样式(如箭头旋转)。可访问性:同时调用notifyAccessibleAttributeChanged(AccessibleAttribute.EXPANDED),通知屏幕阅读器等辅助工具状态变化。它完美复现了ToggleGroup中使用ReadOnlyObjectWrapper封装selectedToggle的模式。4.armed—— 武装状态(用户手势跟踪)publicBooleanPropertyarmedProperty(){returnarmed;}privateBooleanPropertyarmed=newSimpleBooleanProperty(this,"armed",false){@Overrideprotectedvoidinvalidated(){pseudoClassStateChanged(PSEUDO_CLASS_ARMED,get());}};语义:表示鼠标已按下且悬停在控件上,即将触发弹出。这是控件“行为(Behavior)”层面的状态,通常由Skin的鼠标事件监听器修改。作用:区分“误触”(按下后移走)和“真正点击”,提升交互体验。同样利用invalidated()更新伪类:armed。5.promptText—— 提示文本(带输入过滤)privateStringPropertypromptText=newSimpleStringProperty(this,"promptText",null){@Overrideprotectedvoidinvalidated(){Stringtxt=get();if(txt!=nulltxt.contains("\n")){txt=txt.replace("\n","");set(txt);}}};SimpleStringProperty:我们熟悉的SimpleObjectProperty的字符串特化。重写invalidated():当提示文本被设置时,自动移除换行符,防止多行文本破坏单行输入框的布局。这是一个防御性编程的典型例子。6. 事件处理器属性(onAction、onShowing等)privateObjectPropertyEventHandlerActionEventonAction=
返回列表