delphi – 使用命名子组件创建组件?
我需要了解制作组件生成和管理子组件背后的基础知识.我最初通过创建TCollection来尝试这个,并尝试在每个TCollectionItem上添加一个名称.但我知道这并不像我希望的那么容易.
所以现在我将再次从头开始这个项目,这次我想说得对.这些子组件不是可视组件,不应该有任何显示或窗口,只是基于TComponent.保存这些子组件的主要组件也将基于TComponent.所以这里没有什么是视觉的,我不希望在我的表格(设计时间)上为每个子组件添加一个小图标. 我希望能够以类似集合的方式维护和管理这些子组件.重要的是应该创建,命名这些子组件并将其添加到表单源,就像菜单项一样.这是这个想法的重点,如果它们不能被命名,那么整个想法就是kaput. 哦,另一个重要的事情:作为所有子组件的父组件的主要组件需要能够将这些子组件保存到DFM文件中. 例: 而不是访问其中一个子项,如: MyForm.MyItems[1].DoSomething(); 我宁愿喜欢这样做: MyForm.MyItem2.DoSomething(); 所以我不必依赖于知道每个子项的ID. 编辑: 我觉得有必要包含我的原始代码,以便可以看到原始集合的工作原理.这是从整个单元中剥离的服务器端集合和集合项: // Command Collections // Goal: Allow entering pre-set commands with unique Name and ID // Each command has its own event which is triggered when command is received // TODO: Name each collection item as a named component in owner form //Determines how commands are displayed in collection editor in design-time TJDCmdDisplay = (cdName,cdID,cdCaption,cdIDName,cdIDCaption); TJDScktSvrCmdEvent = procedure(Sender: TObject; Socket: TJDServerClientSocket; const Data: TStrings) of object; TSvrCommands = class(TCollection) private fOwner: TPersistent; fOnUnknownCommand: TJDScktSvrCmdEvent; fDisplay: TJDCmdDisplay; function GetItem(Index: Integer): TSvrCommand; procedure SetItem(Index: Integer; Value: TSvrCommand); procedure SetDisplay(const Value: TJDCmdDisplay); protected function GetOwner: TPersistent; override; public constructor Create(AOwner: TPersistent); destructor Destroy; procedure DoCommand(const Socket: TJDServerClientSocket; const Cmd: Integer; const Data: TStrings); function Add: TSvrCommand; property Items[Index: Integer]: TSvrCommand read GetItem write SetItem; published property Display: TJDCmdDisplay read fDisplay write SetDisplay; property OnUnknownCommand: TJDScktSvrCmdEvent read fOnUnknownCommand write fOnUnknownCommand; end; TSvrCommand = class(TCollectionItem) private fID: Integer; fOnCommand: TJDScktSvrCmdEvent; fName: String; fParamCount: Integer; fCollection: TSvrCommands; fCaption: String; procedure SetID(Value: Integer); procedure SetName(Value: String); procedure SetCaption(const Value: String); protected function GetDisplayName: String; override; public procedure Assign(Source: TPersistent); override; constructor Create(Collection: TCollection); override; destructor Destroy; override; published property ID: Integer read fID write SetID; property Name: String read fName write SetName; property Caption: String read fCaption write SetCaption; property ParamCount: Integer read fParamCount write fParamCount; property OnCommand: TJDScktSvrCmdEvent read fOnCommand write fOnCommand; end; //////////////////////////////////////////////////////////////////////////////// implementation //////////////////////////////////////////////////////////////////////////////// { TSvrCommands } function TSvrCommands.Add: TSvrCommand; begin Result:= inherited Add as TSvrCommand; end; constructor TSvrCommands.Create(AOwner: TPersistent); begin inherited Create(TSvrCommand); Self.fOwner:= AOwner; end; destructor TSvrCommands.Destroy; begin inherited Destroy; end; procedure TSvrCommands.DoCommand(const Socket: TJDServerClientSocket; const Cmd: Integer; const Data: TStrings); var X: Integer; C: TSvrCommand; F: Bool; begin F:= False; for X:= 0 to Self.Count - 1 do begin C:= GetItem(X); if C.ID = Cmd then begin F:= True; try if assigned(C.fOnCommand) then C.fOnCommand(Self,Socket,Data); except on e: exception do begin raise Exception.Create( 'Failed to execute command '+IntToStr(Cmd)+': '+#10+e.Message); end; end; Break; end; end; if not F then begin //Command not found end; end; function TSvrCommands.GetItem(Index: Integer): TSvrCommand; begin Result:= TSvrCommand(inherited GetItem(Index)); end; function TSvrCommands.GetOwner: TPersistent; begin Result:= fOwner; end; procedure TSvrCommands.SetDisplay(const Value: TJDCmdDisplay); begin fDisplay := Value; end; procedure TSvrCommands.SetItem(Index: Integer; Value: TSvrCommand); begin inherited SetItem(Index,Value); end; { TSvrCommand } procedure TSvrCommand.Assign(Source: TPersistent); begin inherited; end; constructor TSvrCommand.Create(Collection: TCollection); begin inherited Create(Collection); fCollection:= TSvrCommands(Collection); end; destructor TSvrCommand.Destroy; begin inherited Destroy; end; function TSvrCommand.GetDisplayName: String; begin case Self.fCollection.fDisplay of cdName: begin Result:= fName; end; cdID: begin Result:= '['+IntToStr(fID)+']'; end; cdCaption: begin Result:= fCaption; end; cdIDName: begin Result:= '['+IntToStr(fID)+'] '+fName; end; cdIDCaption: begin Result:= '['+IntToStr(fID)+'] '+fCaption; end; end; end; procedure TSvrCommand.SetCaption(const Value: String); begin fCaption := Value; end; procedure TSvrCommand.SetID(Value: Integer); begin fID:= Value; end; procedure TSvrCommand.SetName(Value: String); begin fName:= Value; end; 解决方法
正如我们昨天讨论的那样,This Thread帮我创造了一些东我拿了包贴在那里并修改了一下.这是来源:
TestComponents.pas unit TestComponents; interface uses Classes; type TParentComponent = class; TChildComponent = class(TComponent) private FParent: TParentComponent; procedure SetParent(const Value: TParentComponent); protected procedure SetParentComponent(AParent: TComponent); override; public destructor Destroy; override; function GetParentComponent: TComponent; override; function HasParent: Boolean; override; property Parent: TParentComponent read FParent write SetParent; end; TParentComponent = class(TComponent) private FChilds: TList; protected procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; property Childs: TList read FChilds; end; implementation { TChildComponent } destructor TChildComponent.Destroy; begin Parent := nil; inherited; end; function TChildComponent.GetParentComponent: TComponent; begin Result := FParent; end; function TChildComponent.HasParent: Boolean; begin Result := Assigned(FParent); end; procedure TChildComponent.SetParent(const Value: TParentComponent); begin if FParent <> Value then begin if Assigned(FParent) then FParent.FChilds.Remove(Self); FParent := Value; if Assigned(FParent) then FParent.FChilds.Add(Self); end; end; procedure TChildComponent.SetParentComponent(AParent: TComponent); begin if AParent is TParentComponent then SetParent(AParent as TParentComponent); end; { TParentComponent } constructor TParentComponent.Create(AOwner: TComponent); begin inherited; FChilds := TList.Create; end; destructor TParentComponent.Destroy; var I: Integer; begin for I := 0 to FChilds.Count - 1 do FChilds[0].Free; FChilds.Free; inherited; end; procedure TParentComponent.GetChildren(Proc: TGetChildProc; Root: TComponent); var i: Integer; begin for i := 0 to FChilds.Count - 1 do Proc(TComponent(FChilds[i])); end; end. TestComponentsReg.pas unit TestComponentsReg; interface uses Classes,DesignEditors,DesignIntf,TestComponents; type TParentComponentEditor = class(TComponentEditor) procedure ExecuteVerb(Index: Integer); override; function GetVerb(Index: Integer): string; override; function GetVerbCount: Integer; override; end; procedure Register; implementation uses ColnEdit; type TChildComponentCollectionItem = class(TCollectionItem) private FChildComponent: TChildComponent; function GetName: string; procedure SetName(const Value: string); protected property ChildComponent: TChildComponent read FChildComponent write FChildComponent; function GetDisplayName: string; override; public constructor Create(Collection: TCollection); override; destructor Destroy; override; published property Name: string read GetName write SetName; end; TChildComponentCollection = class(TOwnedCollection) private FDesigner: IDesigner; public property Designer: IDesigner read FDesigner write FDesigner; end; procedure Register; begin RegisterClass(TChildComponent); RegisterNoIcon([TChildComponent]); RegisterComponents('Test',[TParentComponent]); RegisterComponentEditor(TParentComponent,TParentComponentEditor); end; { TParentComponentEditor } procedure TParentComponentEditor.ExecuteVerb(Index: Integer); var LCollection: TChildComponentCollection; i: Integer; begin LCollection := TChildComponentCollection.Create(Component,TChildComponentCollectionItem); LCollection.Designer := Designer; for i := 0 to TParentComponent(Component).Childs.Count - 1 do with TChildComponentCollectionItem.Create(nil) do begin ChildComponent := TChildComponent(TParentComponent(Component).Childs[i]); Collection := LCollection; end; ShowCollectionEditorClass(Designer,TCollectionEditor,Component,LCollection,'Childs'); end; function TParentComponentEditor.GetVerb(Index: Integer): string; begin Result := 'Edit Childs...'; end; function TParentComponentEditor.GetVerbCount: Integer; begin Result := 1; end; { TChildComponentCollectionItem } constructor TChildComponentCollectionItem.Create(Collection: TCollection); begin inherited; if Assigned(Collection) then begin FChildComponent := TChildComponent.Create(TComponent(TOwnedCollection(Collection).Owner).Owner); FChildComponent.Name := TChildComponentCollection(Collection).Designer.UniqueName(TChildComponent.ClassName); FChildComponent.Parent := TParentComponent(TComponent(TOwnedCollection(Collection).Owner)); end; end; destructor TChildComponentCollectionItem.Destroy; begin FChildComponent.Free; inherited; end; function TChildComponentCollectionItem.GetDisplayName: string; begin Result := FChildComponent.Name; end; function TChildComponentCollectionItem.GetName: string; begin Result := FChildComponent.Name; end; procedure TChildComponentCollectionItem.SetName(const Value: string); begin FChildComponent.Name := Value; end; end. 最重要的是RegisterNoIcon,它可以防止在创建表单时在组件上显示该组件. TChildComponent中重写的方法导致它们嵌套在TParentComponent中. 编辑:我添加了一个临时集合来编辑内置TCollectionEditor中的项目,而不必编写自己的项目.唯一的缺点是TChildComponentCollectionItem必须发布TChildComponent已发布的每个属性,以便能够在OI内编辑它们. (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |