Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations strongm on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

TCollectionItem with a name? 1

Status
Not open for further replies.

djjd47130

Programmer
Nov 1, 2010
480
US
(I posted this as a comment in another thread, but thought I'd create a new one)

I'm just trying to build a TCollection and TCollectionItem set. Each individual TCollectionItem needs to have its own events. However, when I try to assign the published event property of one of these items, I get an error that the item is unnamed. Therefore, How do I give each TCollectionItem a unique name, which can be accessed as if it were a TComponent? I would also need be able to access this item directly from the code, so one collection may have 3 items: cmdOne, cmdTwo, and cmdThree (names), and be able to put somewhere cmdOne.Text:= 'MyText'; and cmdTwo.ExecuteCommand('blah');

Only then will it be able to have unique events. I don't want to have one universal event procedure for all items, and try to filter out with an if or case statement. I want each item to be assigned its own event procedure.

JD Solutions
 
It should work similar to how the TPageControl has a number of TTabSheet objects, each with its own unique name.

JD Solutions
 
Since I got more time to explain...

I'm building two components which wrap a Server Socket and a Client Socket. The original sockets do not have a login, nor do they have any type of command/packet structure. It's all send/receive plain text. What I've done is wrapped that up into a system which can authenticate login, and trigger an event upon full commands received, rather than new data available.

Server Socket Properties:
- Active: Bool
- Port: Integer
- Commands: TSvrCommands
- Name: String
- OnCommand: Event
- OnConnection: Event
- OnError: Event
- OnLoginRequest: Event

Client Socket Properties:
- Active: Bool
- Port: Integer
- Commands: TCliCommands
- Name: String
- Host: String
- Username: String
- Password: String
- OnCommand: Event
- OnConnection: Event
- OnError: Event
- OnLoginResponse: Event

The TCliCommands and TSvrCommands are both a TCollection of TCliCommand and TSvrCommand. I had to separate them because they use specific Server/Client sockets as parameters, but that's another story. Each of these collection items (TCliCommand and TSvrCommand) have the following properties:

- ID: Integer - Represents unique integer value to be passed through socket as command
- Name: String - (THIS IS WHAT I WANT TO GET WORKING) - Unique name for item
- OnCommand: Event - Triggered when this command is to be executed - calls unique procedure to handle the event of a single command

The name property I made, and I can set it, but it does not serve its purpose of an actual component name. Once I get this working, then the event OnCommand will work.




JD Solutions
 
Here's some snapshots of what I have so far...

TSvrCommands.png


JD Solutions
 
I've found actually a WORSE problem which I need to solve here... The items I create inside the collection are NOT being saved with the project. I can create items, set their properties, close the property editor and re-open it, and they're there. But, then I save the project and close it completely, then re-open the project, and all those collection items are gone.

?????????????????

(By the way, I believe I have a work-around for the above without needing to assign a name to the TCollectionItem)

I've done collections before and never had this problem. Here's how it's built:

Code:
type
  TJDScktSvrCmdEvent = procedure(Sender: TObject; Socket: TJDServerClientSocket;
    const Data: TStrings) of object;

  TSvrCommands = class(TCollection)
  private
    fOwner: TJDServerSocket; //This is a custom socket of mine - of course you won't have it
    function GetItem(Index: Integer): TSvrCommand;
    procedure SetItem(Index: Integer; Value: TSvrCommand);
  public
    constructor Create(ASocket: TJDServerSocket);
    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;
  end;

  TSvrCommand = class(TCollectionItem)
  private
    fID: Integer;
    fOnCommand: TJDScktSvrCmdEvent;
    fName: String;
    procedure SetID(Value: Integer);
    procedure SetName(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 OnCommand: TJDScktSvrCmdEvent read fOnCommand write fOnCommand;
  end;

And the implementation:

Code:
{ TSvrCommands }

function TSvrCommands.Add: TSvrCommand;
begin
  Result:= inherited Add as TSvrCommand;
end;

constructor TSvrCommands.Create(ASocket: TJDServerSocket);
begin
  inherited Create(TSvrCommand);
  Self.fOwner:= ASocket;
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;
      if assigned(C.fOnCommand) then begin
        C.fOnCommand(Self, Socket, Data);
      end else begin
        //Procedure not assigned to event - raise exception
      end;
      Break;
    end;
  end;
  if not F then begin
    //Command not found

  end;
end;

function TSvrCommands.GetItem(Index: Integer): TSvrCommand;
begin
  Result:= TSvrCommand(inherited Items[Index]);
end;

procedure TSvrCommands.SetItem(Index: Integer; Value: TSvrCommand);
begin
  inherited Items[Index]:= Value;
end;

{ TSvrCommand }

procedure TSvrCommand.Assign(Source: TPersistent);
begin
  inherited;
  //No need to do anything here at this time
end;

constructor TSvrCommand.Create(Collection: TCollection);
begin
  inherited Create(Collection);

end;

destructor TSvrCommand.Destroy;
begin

  inherited Destroy;
end;

function TSvrCommand.GetDisplayName: String;
begin
  Result:= Name;
end;

procedure TSvrCommand.SetID(Value: Integer);
begin
  fID:= Value;
end;

procedure TSvrCommand.SetName(Value: String);
begin
  fName:= Value;
end;


JD Solutions
 
Seeing as the problem I had has shifted to another problem, I'm actually going to post a more thorough new thread about the saving problem.

If you have any input on the naming issue which this thread was originally made for, please reply here.

If you have any input on the saving issue, please reply in the new thread:



JD Solutions
 
so one collection may have 3 items: cmdOne, cmdTwo, and cmdThree (names), and be able to put somewhere cmdOne.Text:= 'MyText'; and cmdTwo.ExecuteCommand('blah');

It should work similar to how the TPageControl has a number of TTabSheet objects, each with its own unique name.

It's an apples to oranges thing. TTabSheet is a TControl descendant, which by association will have a control name. TCollection does not.

But you really can't make things work in a way they aren't designed through the compiler. Like with an array, you can't alias Myarray[3] to be "ColCount". You have to work with the array item within the source.

TCollection is analogous to TList (out of which comes TStringList), which is just a collection of items. While I'm sure TCollection it has its reasons for existing that are different than TList, I really am not thinking you can "alias" a specific collection item.

However, what seems promising is if you can study and duplicate what is done with the TMenuItem types within the containers for those and duplicate it.

It is not possible for anyone to acknowledge truth when their salary depends on them not doing it.
 
Thanks, I was actually just starting to think to restructure this into a TList of TComponent objects, but I would also need to make my own property editor. I was just hoping that there may be some way to make it easier by use of the TCollection, already having the property editor. Fair enough, I'll see what I can do with that.

JD Solutions
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top