Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Delphi 如何使自定义控件的TList属性可流化?_Delphi - Fatal编程技术网

Delphi 如何使自定义控件的TList属性可流化?

Delphi 如何使自定义控件的TList属性可流化?,delphi,Delphi,概述 我正在编写从TCustomListBox派生的自己的listbox控件 我还开始实现自己的属性编辑器,以允许在设计时编辑项目的标题和imageindex。我正在自定义绘制列表框,并已从控件发布了自己的ImageList属性 问题 到目前为止,一切正常,但我无法将项目流式传输到dfm。我相信这可能是因为标准listbox Items属性是TStrings,并且从我的控件中发布了我自己的属性,该属性也是命名的Items,但属于TList类。我不希望显示listbox的standard Item

概述

我正在编写从TCustomListBox派生的自己的listbox控件

我还开始实现自己的属性编辑器,以允许在设计时编辑项目的标题和imageindex。我正在自定义绘制列表框,并已从控件发布了自己的ImageList属性

问题

到目前为止,一切正常,但我无法将项目流式传输到dfm。我相信这可能是因为标准listbox Items属性是TStrings,并且从我的控件中发布了我自己的属性,该属性也是命名的Items,但属于TList类。我不希望显示listbox的standard Items属性,而是希望显示我自己的Items类型

因此,即使我可以在设计时将控件放到表单上,使用我自己的属性编辑器编辑项,如果我运行应用程序,列表框为空,如果我在设计时查看DFM,然后返回表单视图,这些项也会消失,基本上它们没有存储在DFM中,我不确定如何更正

代码的相关摘录类似于为解决此问题而添加的注释:

我自己的列表框项目类型:

TListBoxItem = class(TObject) // Also tried TPersistent
private
  FCaption: string;
  FImageIndex: Integer;
public // Also tried Published
  property Caption: string read FCaption write FCaption;
  property ImageIndex: Integer read FImageIndex write FImageIndex;
end;
自定义控件:

TMyListBox = class(TCustomListBox)
private
  FImageList: TImageList;
  FItems: TList;
  procedure SetImageList(const Value: TImageList);
protected
  procedure Notification(AComponent: TComponent;
    Operation: TOperation); override;
  procedure DrawItem(Index: Integer; Rect: TRect; State: TOwnerDrawState); Override;
  procedure MeasureItem(Index: Integer; var Height: Integer); override;
public
  constructor Create(AOwner: TComponent); override;
  destructor Destroy; override;

  procedure AddItem(ACaption: string; AImageIndex: Integer); // adds a new item to FItems and the listbox control
published
  .....
  property Color;
  property Images: TImageList read FImageList write SetImageList;
  property Items: TList read FItems write FItems; // take over standard Items type and publish my own Items type instead
  .....
  property Sorted;
  property TabOrder;
  property TabStop;
  property Visible;
  property OnClick;
  property OnContextPopup;
  property OnDblClick;
  property OnDragDrop;
  property OnDragOver;
  //property OnDrawItem;
  property OnEndDock;
  property OnEndDrag;
  property OnEnter;
  property OnExit;
  property OnKeyDown;
  property OnKeyPress;
  property OnKeyUp;
  //property OnMeasureItem;
  property OnMouseDown;
  property OnMouseEnter;
  property OnMouseLeave;
  property OnMouseMove;
  property OnMouseUp;
  .....
end;
这是控件最简单的形式。我想对控件所做的一切,如自定义图形和“我的项目”属性的属性编辑器等,都是按照我的意愿进行的

问题:

我需要做些什么才能使FItems财产流向DFM?DFM应在项目下显示我自己的每个列表框项目类型


谢谢。

有两种可能:

1使用TCollection而不是TList,并且您的项类应该是TCollectionItem的后代。例如,这就是如何在TStatusBar中实现panels属性。如果您的项可以由相同的类组成,并且它们可以是TCollectionItem的后代(TCollectionItem本身是TPersistent的后代),则这种方法更可取。看起来是这样的:

TMyListBoxItem = class (TCollectionItem)
private
  FCaption: string;
  FImageIndex: Integer;
published  //only published properties will be saved to dfm
  property Caption: string read FCaption write FCaption;
  property ImageIndex: Integer read FImageIndex write FImageIndex;
end;

TMyListBoxItemClass = class of TMyListBoxItem; //class reference, or metaclass, we need it to properly initialize TCollection

TMyListBox = class(TCustomListBox)
private
// imageList etc...
  FItems: TCollection;
public
  constructor Create(aOwner: TComponent); override;
  destructor Destroy; override;
  // other funcs
published
  property Items: TCollection read fItems write fItems;
  //other properties
end;

//implementation
constructor TMyListBox.Create(aOwner: TComponent)
begin
  inherited;
  //other initializations
  fItems:=TCollection.Create(TMyListBoxItemClass); //so TCollection is able to create items as many as needed
end;

destructor TMyListBox.destroy;
begin
 fItems.free;
 //other destruction
 inherited Destroy;
end;
基本上就是这样。顺便说一句,当您需要流式传输到dfm时,千万不要从TObject开始,它从TPersistent开始,这正是指它能够被保存,然后加载,并在TComponent中最充分地实现

2每个项都是TControl子体,它以您的自定义列表框作为其父项,窗体作为其所有者。可能TComponent就足够了。在TTabControl、TPageControl、TMainMenu和其他组件中就是这样做的。在这种情况下,项可能也包含它们自己的项,所有这些结构都显示在IDE的“结构”面板中,这非常方便。但在这种情况下,在对象检查器中不能有“Items”属性,而是必须在设计时在弹出菜单中实现自己的按钮,如“Items editor”或“New item”等。
如果项目可以“自行绘制”,具有不同的类型,并且可能有自己的子项,则此实现非常有用。

t收集是srteamable,TList不是,以及您未指定的项目类型。我现在可以按照选项1使用TCollection,而不是TList。非常感谢您的解释和详细的回答。还有第三种选择。让主组件重写virtual DefineProperties方法,为TList数据提供自定义流。请看。@RemyLebeau很有趣,看起来很复杂,我相信这将是一本有趣的读物:谢谢您添加了另一个选项。