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!

Is it possible to use a TCollection within another TCollectionItem? 2

Status
Not open for further replies.

djjd47130

Programmer
Nov 1, 2010
480
US
I'm building a custom component which is using a TCollection. I have the hang of using TCollection, but I tried to implement another TCollection class within another TCollectionItem but it won't work in the property editor. I'm creating it identically the same as I'm creating the other one. It shows in the property editor, but it will not respond. Is it not possible to have a collection within another collection's item? Should I create my own property editor for this? (If so, that's another new project). Please advise...

JD Solutions
 
As for components, you can implement anything you want and use anything you want. If you want it to work with the IDE property editor, however, you have to make a property editor for it. In fact, you have to do that for anything outside the simple variables and a couple of the classes that are used within VCL repeatedly (TIcon and TStrings come to mind).



It is not possible for anyone to acknowledge truth when their salary depends on them not doing it.
 
Thank you, then I need to figure out what's going wrong with this... I think I'll try the property editor, never tried one.

JD Solutions
 
Hopefully you can figure out how to do a property editor. If it helps, here's a simple one for the SHBrowseForFolder component I posted once upon a time.

Here's how the class is defined.
Code:
type
{ TPathName is an explicit path name designed to be connected to a property
  editor which triggers this control.  It must be defined like this so Delphi
  distinguishes it from regular string types in this control and in other
  controls }
  TPathName = String[255];

 // property editor for TPathName within this component
  TPathNameProperty = class(TStringProperty)
    public
      function GetAttributes: TPropertyAttributes; override;
      procedure Edit; override;
    end;

Here's the method definitions. First is for how the field behaves. Second actually makes the change.
Code:
function TPathNameProperty.GetAttributes: TPropertyAttributes;
    // property handler for file dir paths, set attributes for the property
    begin
      Result := [paDialog, paReadOnly];
    end {GetAttributes};

  procedure TPathNameProperty.Edit;
    // property handler for file paths.  Returns directory path.
    var
      lpItemID : PItemIDList;
      DisplayName : array[0..MAX_PATH] of char;
      TempPath : array[0..MAX_PATH] of char;
      FBr: TBrowseInfo;
    begin
      FillChar(FBr, sizeof(TBrowseInfo), #0);
      with FBr do
        begin
          hwndOwner := Application.Handle;
          pszDisplayName := @DisplayName;
          lpszTitle := PChar('Select the value for ' + GetName);
          lpfn := BD_Callback;
          lparam := Longint(PChar(GetValue));
          ulFlags := BIF_RETURNONLYFSDIRS;
        end;
      lpItemID := SHBrowseForFolder(FBr);
      if lpItemId <> nil then
        begin
          if SHGetPathFromIDList(lpItemID, TempPath) then
             SetValue(String(TempPath));
          GlobalFreePtr(lpItemID);
        end
      else
        SetValue('');
    end;

Then you have to register the property editor like you register the component itself into the IDE. The second one makes it so the control is triggered for any TPathName that occurs anywhere as long as the control is installed.
Code:
// this line below isolates the property editor to this control only
//  RegisterPropertyEditor(TypeInfo(TPathName), TDirBrowseDialog, '', TPathNameProperty);
  RegisterPropertyEditor(TypeInfo(TPathName), nil, '', TPathNameProperty)

The unit DsgnIntf is required. Reading that should net a few property editors as well.

It is not possible for anyone to acknowledge truth when their salary depends on them not doing it.
 
You need to use TOwnedCollection instead of TCollection within the TCollectionItem in order for the property editor to work.

 
OR you could override the "GetOwner" method in your TCollection class. This should work as the property editor requires the collection to have an owner component in order to work. No need to create a custom property editor.

Example:

type
TYourCollection = class;

TYourCollectionItem = class(TCollectionItem)
public
constructor Create(ACollection: TCollection); override;
published
property YourCollection: TYourCollection read FYourCollection write FYourCollection;
end;

TYourCollection = class(TCollection)
private
FOwner: TPersistent;
protected
function GetOwner : TPersistent; override;
public
constructor Create(AOwner: TComponent);
end;

constructor TYourCollectionItem.Create(ACollection: TCollection);
begin
inherited Create(ACollection);
FYourCollection := TYourCollection.Create(ACollection.Owner);
end;

constructor TYourCollection.Create(AOwner: TComponent);
begin
inherited Create(TYourCollectionItem);
FOwner := AOwner;
end;

function TYourCollection.GetOwner: TPersistent;
begin
Result := FOwner;
end;
 
I got another question regarding a TCollectionItem.

Is it possible to give a collection item a unique name (not display name) as a Component? Similar to how a TTabSheet works in a TPageControl. You can name the tabs so you can refer to the items by name in the code. I would also need the ability to assign events to each of these items individually, so each one can be assigned its own procedure, rather than sharing the same procedure.

The goal is for a custom server/socket set I'm building, which works fine, but I'd like to make it more flexible. There's currently an event on both sides:

Code:
type
  TCommandEvent = procedure(Sender: TObject; Socket: TJDSocket; 
    const Cmd: Integer; const Data: TStrings) of object;
  
  TMyComponent = class(TComponent)
  private
    fOnCommand: TCommandEvent;
  public

  published
    property OnCommand: TCommandEvent read fOnCommand write fOnCommand;
  end;

What I would like to do is have this event on each individual "Command" item within this collection. In other words, I will have a TCollection property with a group of Commands, each Command having its own unique name and set of properties/events. So, I can have one command on the server side called "cmdLoginRequest" to validate credentials, and another on the client side named "cmdLoginReply" when the server responds to this request... and the possibilities are endless. All I gotta do is give a unique name to the items inside the collection.


JD Solutions
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top