delphi – “无法为未命名的组件创建方法”

前端之家收集整理的这篇文章主要介绍了delphi – “无法为未命名的组件创建方法”前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
以下代码(在包中注册时)为我们提供了一个在托盘Test中注册的名为TParentComponent的组件.

但是,使用属性编辑器(在相同代码中提供)创建Child对象时,IDE将显示错误消息“无法为未命名的组件创建方法”.

奇怪的是Child对象确实有一个名字.

这是来源:

  1. unit TestEditorUnit;
  2.  
  3. interface
  4.  
  5. uses
  6. Classes,DesignEditors,DesignIntf;
  7.  
  8. type
  9. TParentComponent = class;
  10.  
  11. TChildComponent = class(TComponent)
  12. private
  13. FParent: TParentComponent;
  14. FOnTest: TNotifyEvent;
  15. procedure SetParent(const Value: TParentComponent);
  16. protected
  17. procedure SetParentComponent(AParent: TComponent); override;
  18. public
  19. destructor Destroy; override;
  20. function GetParentComponent: TComponent; override;
  21. function HasParent: Boolean; override;
  22. property Parent: TParentComponent read FParent write SetParent;
  23. published
  24. property OnTest: TNotifyEvent read FOnTest write FOnTest;
  25. end;
  26.  
  27. TParentComponent = class(TComponent)
  28. private
  29. FChilds: TList;
  30. protected
  31. procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
  32. public
  33. constructor Create(AOwner: TComponent); override;
  34. destructor Destroy; override;
  35. published
  36. property Childs: TList read FChilds;
  37. end;
  38.  
  39. TParentPropertyEditor = class(TPropertyEditor)
  40. public
  41. function GetAttributes: TPropertyAttributes; override;
  42. function GetValue: string; override;
  43. procedure Edit; override;
  44. end;
  45.  
  46. procedure Register;
  47.  
  48. implementation
  49.  
  50. uses
  51. ColnEdit;
  52.  
  53. type
  54. TChildComponentCollectionItem = class(TCollectionItem)
  55. private
  56. FChildComponent: TChildComponent;
  57. function GetName: string;
  58. function GetOnTest: TNotifyEvent;
  59. procedure SetName(const Value: string);
  60. procedure SetOnTest(const Value: TNotifyEvent);
  61. protected
  62. property ChildComponent: TChildComponent read FChildComponent write FChildComponent;
  63. function GetDisplayName: string; override;
  64. public
  65. constructor Create(Collection: TCollection); override;
  66. destructor Destroy; override;
  67. published
  68. property Name: string read GetName write SetName;
  69. property OnTest: TNotifyEvent read GetOnTest write SetOnTest;
  70. end;
  71.  
  72. TChildComponentCollection = class(TOwnedCollection)
  73. private
  74. FDesigner: IDesigner;
  75. public
  76. property Designer: IDesigner read FDesigner write FDesigner;
  77. end;
  78.  
  79. procedure Register;
  80. begin
  81. RegisterClass(TChildComponent);
  82. RegisterNoIcon([TChildComponent]);
  83. RegisterComponents('Test',[TParentComponent]);
  84. RegisterPropertyEditor(TypeInfo(TList),TParentComponent,'Childs',TParentPropertyEditor);
  85. end;
  86.  
  87. { TChildComponent }
  88.  
  89. destructor TChildComponent.Destroy;
  90. begin
  91. Parent := nil;
  92. inherited;
  93. end;
  94.  
  95. function TChildComponent.GetParentComponent: TComponent;
  96. begin
  97. Result := FParent;
  98. end;
  99.  
  100. function TChildComponent.HasParent: Boolean;
  101. begin
  102. Result := Assigned(FParent);
  103. end;
  104.  
  105. procedure TChildComponent.SetParent(const Value: TParentComponent);
  106. begin
  107. if FParent <> Value then
  108. begin
  109. if Assigned(FParent) then
  110. FParent.FChilds.Remove(Self);
  111. FParent := Value;
  112. if Assigned(FParent) then
  113. FParent.FChilds.Add(Self);
  114. end;
  115. end;
  116.  
  117. procedure TChildComponent.SetParentComponent(AParent: TComponent);
  118. begin
  119. if AParent is TParentComponent then
  120. SetParent(AParent as TParentComponent);
  121. end;
  122.  
  123. { TParentComponent }
  124.  
  125. constructor TParentComponent.Create(AOwner: TComponent);
  126. begin
  127. inherited;
  128. FChilds := TList.Create;
  129. end;
  130.  
  131. destructor TParentComponent.Destroy;
  132. var
  133. I: Integer;
  134. begin
  135. for I := 0 to FChilds.Count - 1 do
  136. TComponent(FChilds[0]).Free;
  137. FChilds.Free;
  138. inherited;
  139. end;
  140.  
  141. procedure TParentComponent.GetChildren(Proc: TGetChildProc; Root: TComponent);
  142. var
  143. i: Integer;
  144. begin
  145. for i := 0 to FChilds.Count - 1 do
  146. Proc(TComponent(FChilds[i]));
  147. end;
  148.  
  149. { TChildComponentCollectionItem }
  150.  
  151. constructor TChildComponentCollectionItem.Create(Collection: TCollection);
  152. begin
  153. inherited;
  154. if Assigned(Collection) then
  155. begin
  156. FChildComponent := TChildComponent.Create(TComponent(TOwnedCollection(Collection).Owner).Owner);
  157. FChildComponent.Name := TChildComponentCollection(Collection).Designer.UniqueName(TChildComponent.ClassName);
  158. FChildComponent.Parent := TParentComponent(TComponent(TOwnedCollection(Collection).Owner));
  159. end;
  160. end;
  161.  
  162. destructor TChildComponentCollectionItem.Destroy;
  163. begin
  164. FChildComponent.Free;
  165. inherited;
  166. end;
  167.  
  168. function TChildComponentCollectionItem.GetDisplayName: string;
  169. begin
  170. Result := FChildComponent.Name;
  171. end;
  172.  
  173. function TChildComponentCollectionItem.GetName: string;
  174. begin
  175. Result := FChildComponent.Name;
  176. end;
  177.  
  178. function TChildComponentCollectionItem.GetOnTest: TNotifyEvent;
  179. begin
  180. Result := FChildComponent.OnTest;
  181. end;
  182.  
  183. procedure TChildComponentCollectionItem.SetName(const Value: string);
  184. begin
  185. FChildComponent.Name := Value;
  186. end;
  187.  
  188. procedure TChildComponentCollectionItem.SetOnTest(const Value: TNotifyEvent);
  189. begin
  190. FChildComponent.OnTest := Value;
  191. end;
  192.  
  193. { TParentPropertyEditor }
  194.  
  195. procedure TParentPropertyEditor.Edit;
  196. var
  197. LCollection: TChildComponentCollection;
  198. i: Integer;
  199. begin
  200. LCollection := TChildComponentCollection.Create(GetComponent(0),TChildComponentCollectionItem);
  201. LCollection.Designer := Designer;
  202. for i := 0 to TParentComponent(GetComponent(0)).Childs.Count - 1 do
  203. with TChildComponentCollectionItem.Create(nil) do
  204. begin
  205. ChildComponent := TChildComponent(TParentComponent(GetComponent(0)).Childs[i]);
  206. Collection := LCollection;
  207. end;
  208. ShowCollectionEditorClass(Designer,TCollectionEditor,TComponent(GetComponent(0)),LCollection,'Childs');
  209. end;
  210.  
  211. function TParentPropertyEditor.GetAttributes: TPropertyAttributes;
  212. begin
  213. Result := [paDialog];
  214. end;
  215.  
  216. function TParentPropertyEditor.GetValue: string;
  217. begin
  218. Result := 'Childs';
  219. end;
  220.  
  221. end.

上述来源改编自another answer here on StackOverflow.

任何想法为什么我不能为OnTest创建一个方法

提前致谢!

解决方法

设计时间要求摘要

>您想要或需要一个能够容纳多个子组件的自定义组件.
>这些子组件将由该自定义组件创建.
>子组件需要能够在代码中通过其名称引用为设计时的任何正常组件;因此不是Form.CustomComponent.Children [0],而是Form.Child1.
>因此,子组件需要声明 – 并因此添加到 – 模块的源文件(Form,Frame或DataModule).
>子组件将由默认IDE集合编辑器管理.
>因此,孩子需要完全包装到TCollectionItem中.

评估当前代码

你已经很顺利了,但除了你的问题,代码还有一些需要改进的地方:

>您创建的集合永远不会被释放.
>每次显示集合编辑器时都会创建一个新集合.
>如果从TreeView中删除子项,则旧的相应CollectionItem将保留,从而生成AV.
>设计时间和运行时代码不分割.

以下是代码的重写工作版本,其中包含以下更改:

>特殊组件称为Master,因为Parent与Delphi的Parent混淆太多(已经有两种类型).因此,一个孩子被称为奴隶.
> Slave被保存在TComponentList(单元Contnrs)中,以便在单个从站销毁时自动更新列表. ComponentList拥有从属.
>对于每个Master,只创建一个Collection.这些Master-Collection组合保存在单独的TStockItems ObjectList中.列表拥有库存项目,并在“完成”部分中释放列表.
>实现GetNamePath,以便在Object Inspector中将slave显示为Slave1,而不是SlaveWrappers(0).
>为TSlaveWrapper类的事件添加了额外的属性编辑器.不知何故,默认TMethodProperty的GetFormMethodName会导致您获得的错误.原因将在Designer.GetObjectName中,但我不确切知道原因.现在GetFormMethodName被覆盖,这解决了您的问题中的问题.

备注

按集合中项目的顺序(使用集合编辑器的箭头按钮)所做的更改尚未保留.试着让自己实现.

在TreeView中,每个Slave现在都是Master的直接子节点,而不是Slaves属性的子节点,正如通常在集合中看到的那样:

为了实现这一点,我认为TSlaves应该来自TPersistent,并且ComponentList将被包含在其中.这肯定是另一个不错的尝试.

组件代码

  1. unit MasterSlave;
  2.  
  3. interface
  4.  
  5. uses
  6. Classes,Contnrs;
  7.  
  8. type
  9. TMaster = class;
  10.  
  11. TSlave = class(TComponent)
  12. private
  13. FMaster: TMaster;
  14. FOnTest: TNotifyEvent;
  15. procedure SetMaster(Value: TMaster);
  16. protected
  17. procedure SetParentComponent(AParent: TComponent); override;
  18. public
  19. function GetParentComponent: TComponent; override;
  20. function HasParent: Boolean; override;
  21. property Master: TMaster read FMaster write SetMaster;
  22. published
  23. property OnTest: TNotifyEvent read FOnTest write FOnTest;
  24. end;
  25.  
  26. TSlaves = class(TComponentList)
  27. private
  28. function GetItem(Index: Integer): TSlave;
  29. procedure SetItem(Index: Integer; Value: TSlave);
  30. public
  31. property Items[Index: Integer]: TSlave read GetItem write SetItem; default;
  32. end;
  33.  
  34. TMaster = class(TComponent)
  35. private
  36. FSlaves: TSlaves;
  37. protected
  38. procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override;
  39. public
  40. constructor Create(AOwner: TComponent); override;
  41. destructor Destroy; override;
  42. published
  43. property Slaves: TSlaves read FSlaves;
  44. end;
  45.  
  46. implementation
  47.  
  48. { TSlave }
  49.  
  50. function TSlave.GetParentComponent: TComponent;
  51. begin
  52. Result := FMaster;
  53. end;
  54.  
  55. function TSlave.HasParent: Boolean;
  56. begin
  57. Result := FMaster <> nil;
  58. end;
  59.  
  60. procedure TSlave.SetMaster(Value: TMaster);
  61. begin
  62. if FMaster <> Value then
  63. begin
  64. if FMaster <> nil then
  65. FMaster.FSlaves.Remove(Self);
  66. FMaster := Value;
  67. if FMaster <> nil then
  68. FMaster.FSlaves.Add(Self);
  69. end;
  70. end;
  71.  
  72. procedure TSlave.SetParentComponent(AParent: TComponent);
  73. begin
  74. if AParent is TMaster then
  75. SetMaster(TMaster(AParent));
  76. end;
  77.  
  78. { TSlaves }
  79.  
  80. function TSlaves.GetItem(Index: Integer): TSlave;
  81. begin
  82. Result := TSlave(inherited Items[Index]);
  83. end;
  84.  
  85. procedure TSlaves.SetItem(Index: Integer; Value: TSlave);
  86. begin
  87. inherited Items[Index] := Value;
  88. end;
  89.  
  90. { TMaster }
  91.  
  92. constructor TMaster.Create(AOwner: TComponent);
  93. begin
  94. inherited Create(AOwner);
  95. FSlaves := TSlaves.Create(True);
  96. end;
  97.  
  98. destructor TMaster.Destroy;
  99. begin
  100. FSlaves.Free;
  101. inherited Destroy;
  102. end;
  103.  
  104. procedure TMaster.GetChildren(Proc: TGetChildProc; Root: TComponent);
  105. var
  106. I: Integer;
  107. begin
  108. for I := 0 to FSlaves.Count - 1 do
  109. Proc(FSlaves[I]);
  110. end;
  111.  
  112. end.

编辑代码

  1. unit MasterSlaveEdit;
  2.  
  3. interface
  4.  
  5. uses
  6. Classes,SysUtils,MasterSlave,Contnrs,DesignIntf,ColnEdit;
  7.  
  8. type
  9. TMasterEditor = class(TComponentEditor)
  10. private
  11. function Master: TMaster;
  12. public
  13. procedure ExecuteVerb(Index: Integer); override;
  14. function GetVerb(Index: Integer): String; override;
  15. function GetVerbCount: Integer; override;
  16. end;
  17.  
  18. TMasterProperty = class(TPropertyEditor)
  19. private
  20. function Master: TMaster;
  21. public
  22. procedure Edit; override;
  23. function GetAttributes: TPropertyAttributes; override;
  24. function GetValue: String; override;
  25. end;
  26.  
  27. TOnTestProperty = class(TMethodProperty)
  28. private
  29. function Slave: TSlave;
  30. public
  31. function GetFormMethodName: String; override;
  32. end;
  33.  
  34. TSlaveWrapper = class(TCollectionItem)
  35. private
  36. FSlave: TSlave;
  37. function GetName: String;
  38. function GetOnTest: TNotifyEvent;
  39. procedure SetName(const Value: String);
  40. procedure SetOnTest(Value: TNotifyEvent);
  41. protected
  42. function GetDisplayName: String; override;
  43. public
  44. constructor Create(Collection: TCollection); override;
  45. constructor CreateSlave(Collection: TCollection; ASlave: TSlave);
  46. destructor Destroy; override;
  47. function GetNamePath: String; override;
  48. published
  49. property Name: String read GetName write SetName;
  50. property OnTest: TNotifyEvent read GetOnTest write SetOnTest;
  51. end;
  52.  
  53. TSlaveWrappers = class(TOwnedCollection)
  54. private
  55. function GetItem(Index: Integer): TSlaveWrapper;
  56. public
  57. property Items[Index: Integer]: TSlaveWrapper read GetItem; default;
  58. end;
  59.  
  60. implementation
  61.  
  62. type
  63. TStockItem = class(TComponent)
  64. protected
  65. Collection: TSlaveWrappers;
  66. Designer: IDesigner;
  67. Master: TMaster;
  68. procedure Notification(AComponent: TComponent; Operation: TOperation);
  69. override;
  70. public
  71. destructor Destroy; override;
  72. end;
  73.  
  74. TStockItems = class(TObjectList)
  75. private
  76. function GetItem(Index: Integer): TStockItem;
  77. protected
  78. function CollectionOf(AMaster: TMaster; Designer: IDesigner): TCollection;
  79. function Find(ACollection: TCollection): TStockItem;
  80. property Items[Index: Integer]: TStockItem read GetItem;
  81. default;
  82. end;
  83.  
  84. var
  85. FStock: TStockItems = nil;
  86.  
  87. function Stock: TStockItems;
  88. begin
  89. if FStock = nil then
  90. FStock := TStockItems.Create(True);
  91. Result := FStock;
  92. end;
  93.  
  94. { TStockItem }
  95.  
  96. destructor TStockItem.Destroy;
  97. begin
  98. Collection.Free;
  99. inherited Destroy;
  100. end;
  101.  
  102. procedure TStockItem.Notification(AComponent: TComponent;
  103. Operation: TOperation);
  104. var
  105. I: Integer;
  106. begin
  107. inherited Notification(AComponent,Operation);
  108. if Operation = opRemove then
  109. for I := 0 to Collection.Count - 1 do
  110. if Collection[I].FSlave = AComponent then
  111. begin
  112. Collection[I].FSlave := nil;
  113. Collection.Delete(I);
  114. Break;
  115. end;
  116. end;
  117.  
  118. { TStockItems }
  119.  
  120. function TStockItems.CollectionOf(AMaster: TMaster;
  121. Designer: IDesigner): TCollection;
  122. var
  123. I: Integer;
  124. Item: TStockItem;
  125. begin
  126. Result := nil;
  127. for I := 0 to Count - 1 do
  128. if Items[I].Master = AMaster then
  129. begin
  130. Result := Items[I].Collection;
  131. Break;
  132. end;
  133. if Result = nil then
  134. begin
  135. Item := TStockItem.Create(nil);
  136. Item.Master := AMaster;
  137. Item.Designer := Designer;
  138. Item.Collection := TSlaveWrappers.Create(AMaster,TSlaveWrapper);
  139. for I := 0 to AMaster.Slaves.Count - 1 do
  140. begin
  141. TSlaveWrapper.CreateSlave(Item.Collection,AMaster.Slaves[I]);
  142. Item.FreeNotification(AMaster.Slaves[I]);
  143. end;
  144. Add(Item);
  145. Result := Item.Collection;
  146. end;
  147. end;
  148.  
  149. function TStockItems.GetItem(Index: Integer): TStockItem;
  150. begin
  151. Result := TStockItem(inherited Items[Index]);
  152. end;
  153.  
  154. function TStockItems.Find(ACollection: TCollection): TStockItem;
  155. var
  156. I: Integer;
  157. begin
  158. Result := nil;
  159. for I := 0 to Count - 1 do
  160. if Items[I].Collection = ACollection then
  161. begin
  162. Result := Items[I];
  163. Break;
  164. end;
  165. end;
  166.  
  167. { TMasterEditor }
  168.  
  169. procedure TMasterEditor.ExecuteVerb(Index: Integer);
  170. begin
  171. case Index of
  172. 0: ShowCollectionEditor(Designer,Master,Stock.CollectionOf(Master,Designer),'Slaves');
  173. end;
  174. end;
  175.  
  176. function TMasterEditor.GetVerb(Index: Integer): String;
  177. begin
  178. case Index of
  179. 0: Result := 'Edit slaves...';
  180. else
  181. Result := '';
  182. end;
  183. end;
  184.  
  185. function TMasterEditor.GetVerbCount: Integer;
  186. begin
  187. Result := 1;
  188. end;
  189.  
  190. function TMasterEditor.Master: TMaster;
  191. begin
  192. Result := TMaster(Component);
  193. end;
  194.  
  195. { TMasterProperty }
  196.  
  197. procedure TMasterProperty.Edit;
  198. begin
  199. ShowCollectionEditor(Designer,'Slaves');
  200. end;
  201.  
  202. function TMasterProperty.GetAttributes: TPropertyAttributes;
  203. begin
  204. Result := [paDialog];
  205. end;
  206.  
  207. function TMasterProperty.GetValue: String;
  208. begin
  209. Result := Format('(%s)',[Master.Slaves.ClassName]);
  210. end;
  211.  
  212. function TMasterProperty.Master: TMaster;
  213. begin
  214. Result := TMaster(GetComponent(0));
  215. end;
  216.  
  217. { TOnTestProperty }
  218.  
  219. function TOnTestProperty.GetFormMethodName: String;
  220. begin
  221. Result := Slave.Name + GetTrimmedEventName;
  222. end;
  223.  
  224. function TOnTestProperty.Slave: TSlave;
  225. begin
  226. Result := TSlaveWrapper(GetComponent(0)).FSlave;
  227. end;
  228.  
  229. { TSlaveWrapper }
  230.  
  231. constructor TSlaveWrapper.Create(Collection: TCollection);
  232. begin
  233. CreateSlave(Collection,nil);
  234. end;
  235.  
  236. constructor TSlaveWrapper.CreateSlave(Collection: TCollection; ASlave: TSlave);
  237. var
  238. Item: TStockItem;
  239. begin
  240. inherited Create(Collection);
  241. if ASlave = nil then
  242. begin
  243. Item := Stock.Find(Collection);
  244. FSlave := TSlave.Create(Item.Master.Owner);
  245. FSlave.Name := Item.Designer.UniqueName(TSlave.ClassName);
  246. FSlave.Master := Item.Master;
  247. FSlave.FreeNotification(Item);
  248. end
  249. else
  250. FSlave := ASlave;
  251. end;
  252.  
  253. destructor TSlaveWrapper.Destroy;
  254. begin
  255. FSlave.Free;
  256. inherited Destroy;
  257. end;
  258.  
  259. function TSlaveWrapper.GetDisplayName: String;
  260. begin
  261. Result := Name;
  262. end;
  263.  
  264. function TSlaveWrapper.GetName: String;
  265. begin
  266. Result := FSlave.Name;
  267. end;
  268.  
  269. function TSlaveWrapper.GetNamePath: String;
  270. begin
  271. Result := FSlave.GetNamePath;
  272. end;
  273.  
  274. function TSlaveWrapper.GetOnTest: TNotifyEvent;
  275. begin
  276. Result := FSlave.OnTest;
  277. end;
  278.  
  279. procedure TSlaveWrapper.SetName(const Value: String);
  280. begin
  281. FSlave.Name := Value;
  282. end;
  283.  
  284. procedure TSlaveWrapper.SetOnTest(Value: TNotifyEvent);
  285. begin
  286. FSlave.OnTest := Value;
  287. end;
  288.  
  289. { TSlaveWrappers }
  290.  
  291. function TSlaveWrappers.GetItem(Index: Integer): TSlaveWrapper;
  292. begin
  293. Result := TSlaveWrapper(inherited Items[Index]);
  294. end;
  295.  
  296. initialization
  297.  
  298. finalization
  299. FStock.Free;
  300.  
  301. end.

注册

  1. unit MasterSlaveReg;
  2.  
  3. interface
  4.  
  5. uses
  6. Classes,MasterSlaveEdit,DesignIntf;
  7.  
  8. procedure Register;
  9.  
  10. implementation
  11.  
  12. procedure Register;
  13. begin
  14. RegisterClass(TSlave);
  15. RegisterNoIcon([TSlave]);
  16. RegisterComponents('Samples',[TMaster]);
  17. RegisterComponentEditor(TMaster,TMasterEditor);
  18. RegisterPropertyEditor(TypeInfo(TSlaves),TMaster,'Slaves',TMasterProperty);
  19. RegisterPropertyEditor(TypeInfo(TNotifyEvent),TSlaveWrapper,'OnTest',TOnTestProperty);
  20. end;
  21.  
  22. end.

包裹代码

  1. requires
  2. rtl,DesignIDE;
  3.  
  4. contains
  5. MasterSlave in 'MasterSlave.pas',MasterSlaveEdit in 'MasterSlaveEdit.pas',MasterSlaveReg in 'MasterSlaveReg.pas';

猜你在找的Delphi相关文章