自定义绘制TCustomListbox项目

maa*_*nus 6 delphi vcl firemonkey delphi-10.2-tokyo

我正在重写一个VCL组件,显示TCustomListbox在Delphi 10.2中定制的Firemonkey.自定义使用了重写DrawItem,基本上添加了一些缩进并根据项目文本和索引设置文本颜色.

DrawItem让它变得相当容易,但在FMX中似乎没有这样的东西.我可以PaintChildren自己覆盖和绘制每个项目,但是它看起来不同,我必须自己处理滚动和一切.我刚刚开始使用FMX并且还没有源代码.

  • DrawItemFMX中有替代品吗?我可能错过了它.

  • 如果没有,它如何获得所需信息?基本上,要绘制的矩形和理想的使用样式.

问题

Hans的解决方案有效,但有一些重大问题:

颜色

设置颜色不起作用,文本始终为黑色.我尝试了各种可能性,包括这个:

PROCEDURE TMyItem.Paint;
BEGIN
  TextSettings.FontColor := TAlphaColorRec.Red;
  INHERITED;
END;
Run Code Online (Sandbox Code Playgroud)

速度

打开一个包含180个项目的框可能需要两秒钟.我们需要很多项目和它们的数量实际上是我们需要一个自定义框的原因(我们使用TEdit我们组件的一部分提供过滤).使用字符串的版本TMyItem更快(虽然可能比VCL版本慢),但使用这些项目似乎会减慢速度(它比填充类似的HTML列表慢).

或者是其他东西?没有来源,几乎没有文件,我无法分辨.

我试图缓存项目以供重用,但这没有帮助.

看起来使用自定义项实际上比使用字符串更快(以毫秒为单位):

nItems String TMyItem
   200    672      12
  2000   5604     267
 20000  97322   18700
Run Code Online (Sandbox Code Playgroud)

当内容多次更改时,速度问题似乎会累积.我正在使用FListBox.Items.Clear;,然后我尝试了

n := FListBox.Items.Count;
FOR i := 0 TO n-1 DO FListBox.ListItems[n-1-i].Free;
Run Code Online (Sandbox Code Playgroud)

最后FListBox.Clear;,这是最有意义的(我最后发现).最后,每件物品似乎需要2毫秒.

Han*_*ans 2

以下是如何完成此操作的示例。关键是将Parent(自定义)的设置ListBoxItem为ListBox。这会将其附加到其项目列表中。我在构造函数中设置了父级,因此每次向列表框中添加内容时都不必执行此操作(并记住它)。

type
  tMyListBoxItem = class(TListBoxItem)
  strict private
    fTextLabel: TLabel;
  public
    constructor Create(aOwner: TComponent);
    property TextLabel: TLabel read fTextLabel;
  end;

implementation

constructor tMyListBoxItem.Create(aOwner: TComponent);
begin
  inherited;
  fTextLabel := TLabel.Create(self);
  fTextLabel.Parent := self;
  Assert(aOwner is TFMXObject, 'tMyListBoxItem.Create');
  Parent := TFMXObject(aOwner);
end;

procedure tMyForm.FillListBox(aListBox: TListBox; aStringList: TStringList);
var
  lItem: tMyListBoxItem;
  i: integer;
begin
  aListBox.BeginUpdate; //to avoid repainting for every item added
  aListBox.Clear;
  for i := 0 to aStringList.Count-1 do
  begin
    lItem := tMyListBoxItem.Create(aListBox);
    lItem.TextLabel.Text := aStringList[i];
    lItem.Margins.Left := 20;
  end;
  aListBox.EndUpdate;
end;
Run Code Online (Sandbox Code Playgroud)

我现在在很多地方使用自定义 ListBoxItems,因为您可以在 ListboxItem 中拥有 ComboBox、EditBox 和所有其他控件。这将打开一个非常动态(基于列表)的屏幕布局,可以轻松适应所有平台和屏幕尺寸。