FireMonkey中如何访问TComboBox与TComboEdit内TListBox的VScrollBar?
解决FMX中TComboBox/TComboEdit的ListBox滚动条Thumb事件自定义问题
方法一:直接枚举ListBox的所有子控件(推荐)
无需直接访问受保护的VScrollBar,利用EnumControls的递归枚举特性,直接在ListBox上调用该方法,即可遍历到嵌套在VScrollBar内的TThumb:
class TScrollThumb : public TCppInterfacedObject<TFunc__2<TControl*, TEnumControlsResult>> { public: TEnumControlsResult __fastcall Invoke(TControl* Control) { if (Control->ClassNameIs("TThumb")) { Control->OnMouseEnter = MouseEnter; Control->OnMouseLeave = MouseLeave; Control->OnMouseDown = MouseDown; Control->OnMouseUp = MouseUp; return TEnumControlsResult::Stop; } return TEnumControlsResult::Continue; } }; // 直接在ListBox上调用EnumControls,递归查找TThumb if (ComboBox->ListBox) { ComboBox->ListBox->EnumControls(new TScrollThumb); }
EnumControls默认会递归遍历所有子控件(包括VScrollBar及其内部的TThumb),因此无需提前获取VScrollBar实例,即可定位到目标控件。
方法二:通过RTTI访问受保护的VScrollBar成员
如果需要明确先获取VScrollBar再查找TThumb,可以利用RTTI(运行时类型信息)读取TCustomScrollBox的受保护成员VScrollBar:
#include <System.Rtti.hpp> TScrollBar* GetScrollBoxVScrollBar(TCustomScrollBox* ScrollBox) { if (!ScrollBox) return nullptr; TRttiContext RttiCtx; TRttiType* RttiType = RttiCtx.GetType(ScrollBox->ClassType()); TRttiField* VScrollBarField = RttiType->GetField("VScrollBar"); if (VScrollBarField) { return static_cast<TScrollBar*>(VScrollBarField->GetValue(ScrollBox).AsObject()); } return nullptr; } // 使用方式 TScrollBar* scrollBar = GetScrollBoxVScrollBar(ComboBox->ListBox); if (scrollBar) { scrollBar->EnumControls(new TScrollThumb); }
注意事项
- 不建议修改FMX官方源码将
VScrollBar或GetVScrollBar()改为公开,这会破坏封装性,且可能因编译依赖、版本更新等问题导致后续维护困难。 - 两种方法均兼容TComboBox和TComboEdit的ListBox控件,原理与TVertScrollBox的场景一致,只是跳过了直接访问受保护成员的步骤。
内容的提问来源于stack exchange,提问作者Bruce
相关产品推荐
相关产品推荐

