Necesito saber los fundamentos detrás de hacer un componente producir y administrar subcomponentes. Intenté esto originalmente al crear un TCollection
, e intenté poner un nombre en cada TCollectionItem
. Pero aprendí que no es tan fácil como esperaba.¿Cómo crear un componente con subcomponentes con nombre?
Así que ahora voy a comenzar este proyecto desde cero nuevamente, y me gustaría hacerlo bien esta vez. Estos subcomponentes no son componentes visuales, y no deberían tener ninguna pantalla o ventana, solo basados en TComponent
. El componente principal que contiene estos subcomponentes también se basará en TComponent
. Entonces, nada aquí es visual en absoluto, y no quiero un pequeño icono en mi formulario (en tiempo de diseño) para cada uno de estos subcomponentes.
Me gustaría poder mantener y administrar estos subcomponentes de forma similar a la colección. Lo importante es que estos subcomponentes deben crearse, nombrarse y agregarse al origen del formulario, al igual que los elementos del menú, por ejemplo. Este es el objetivo principal de la idea, en primer lugar, si no pueden nombrarse, entonces toda esta idea es kaput.
Ah, otra cosa importante: el componente principal que es el padre de todos los subcomponentes debe ser capaz de guardar estos subcomponentes en el archivo DFM.
Ejemplo:
lugar de acceder a uno de estos sub elementos como:
MyForm.MyItems[1].DoSomething();
En vez de ello gustaría hacer algo como:
MyForm.MyItem2.DoSomething();
Así que no tengo confiar en conocer la ID de cada sub artículo.
EDIT:
me sentí un poco necesario incluir mi código original por lo que se puede ver cómo funciona la colección original. Aquí es sólo el elemento de la colección del lado del servidor y la recogida despojado de la unidad completa:
// 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;
Podría estudiar el código fuente de las tres "cosas existentes similares" que citó. ¿Cómo implementaron esto los desarrolladores de Delphi? –
Ahora después de su edición, queda claro qué es exactamente lo que desea: No, esto no es posible. Pero dudo que este sea realmente tu deseo. ¿Por qué quieres abordar el elemento de la colección por nombre en el código? – NGLN
Quizás no sea el elemento de la colección real al que se hace referencia desde el código, sino que crea algún componente invisible detrás de cada elemento de la colección que tiene un nombre que se guardará en el DFM. Sin embargo, como se menciona en otro comentario a continuación en su respuesta, no estoy seguro de cómo mostrar las propiedades de ese componente en el inspector de objetos cuando ya se muestran las propiedades de TCollectionItem? –