Delphi 10.2下VCL自定义TCustomListbox迁移FMX的绘图问题
从VCL自定义ListBox转FMX的最佳实践
刚从VCL转FMX确实会遇到不少API逻辑差异的问题,我之前也踩过类似的坑,完全没必要去重写PaintChildren(那会把滚动、布局这些底层逻辑全丢给你,工作量陡增),FMX其实有更贴合VCL DrawItem逻辑的方案,给你两个最实用的方向:
1. 直接用TListBox的OnDrawItem事件(最接近VCL的DrawItem)
FMX的TListBox内置了OnDrawItem事件,专门用来自定义每个列表项的绘制,ListBox会自动帮你处理滚动、选中状态、布局这些底层细节,你只需要专注于每个项的绘制逻辑,和VCL的DrawItem用法几乎一致。
举个贴合你需求的代码示例(实现按索引缩进+自定义文本颜色):
procedure TYourForm.YourListBoxDrawItem(Sender: TCustomListBox; Index: Integer; const ARect: TRectF; State: TListItemDrawStates); var LItemText: string; LIndentOffset: Single; LCanvas: TCanvas; begin LCanvas := Sender.Canvas; LItemText := Sender.Items[Index]; // 1. 处理背景绘制(根据选中状态区分) if TListItemDrawState.Selected in State then LCanvas.Fill.Color := TAlphaColors.LightSteelBlue else LCanvas.Fill.Color := TAlphaColors.White; LCanvas.FillRect(ARect, 0, 0, [], 1); // 填充Item区域 // 2. 设置缩进(比如每级索引缩进20像素) LIndentOffset := Index * 20; // 3. 设置文本颜色(比如奇数索引用红色,偶数用黑色) if Index mod 2 = 0 then LCanvas.Fill.Color := TAlphaColors.Black else LCanvas.Fill.Color := TAlphaColors.DarkRed; // 4. 绘制带缩进的文本 LCanvas.FillText( RectF(ARect.Left + LIndentOffset, ARect.Top, ARect.Right, ARect.Bottom), LItemText, False, // 是否换行 1, // 透明度 [], // 字间距 TTextAlign.Leading, // 水平对齐 TTextAlign.Center // 垂直居中 ); end;
只需要给你的ListBox绑定这个事件,就能实现和VCL DrawItem一样的效果,完全不用管滚动、Item复用这些细节。
2. 封装成自定义ListBox组件(适合复用场景)
如果这个自定义逻辑需要在多个地方复用,你可以创建一个继承自TListBox的自定义组件,重写它的DoDrawItem方法,把绘制逻辑封装进去:
type TMyCustomListBox = class(TListBox) protected procedure DoDrawItem(Index: Integer; const ARect: TRectF; State: TListItemDrawStates); override; end; procedure TMyCustomListBox.DoDrawItem(Index: Integer; const ARect: TRectF; State: TListItemDrawStates); var LItemText: string; LIndentOffset: Single; LCanvas: TCanvas; begin LCanvas := Self.Canvas; LItemText := Self.Items[Index]; // 这里写和上面事件里一样的绘制逻辑 // 处理背景、缩进、文本颜色... // 如果需要保留FMX默认的部分绘制逻辑,可以调用inherited; // inherited; end;
这样你在设计时直接拖这个自定义组件就能用,不用每次都绑定事件。
为什么不用PaintChildren?
PaintChildren是用来绘制所有子控件的,FMX的ListBox内部已经用它来管理Item的绘制和布局了,你重写它等于要自己实现Item的定位、滚动时的重绘、选中状态的维护等等,工作量巨大,完全是舍近求远。
内容的提问来源于stack exchange,提问作者maaartinus
相关产品推荐
相关产品推荐

