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 John Tel on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Using Tag Property with pointer 1

Status
Not open for further replies.

DonTwo

Programmer
Jun 2, 2003
5
GB
I need to store a Record or small array in the Tag property of objects. I am looping and assigning a number to each tag, but I need to have several pieces of information on each tag as in a record and of course each record is the same format but different values in the fields. One of these fields will now be the number mentioned above.
I believe this can be done with pointers but am ignorant of the method and reasoning.

Can you please assist. This is with Delphi 5.
Thanks
 

You can create your own object and store the address in the tag property cast as an integer. When retrieving the address from the tag, simply cast it to the correct object type.

This code is not tested, but it should give you the idea. (If you don't know how to create your own objects, you will need to learn that before this makes any sense.)
Code:
procedure CreateAndStoreMyObject;
var
  oMyObject:TMyObject;
begin
  oMyObject := TMyObject.Create;
  Edit1.Tag := Integer(oMyObject);
end;

procedure RetrieveAndDestroyMyObject;
var
  oMyObject:TMyObject;
begin
  oMyObject := TMyObject(Edit1.Tag);
  oMyObject.Free;
end;
 
Thank you Zathras
Further assistance would be appreciated because this isn't exactly what I am after.
I have no problem creating objects or inheriting from them but I am unable to make the leap in the code you provide to an array or record.
In essence I am simply trying to expand the tag property to take more and diverse information in a situation where I cannot add these fields to the original sprite object as properties (which would be simpler) because the sprites are produced by an object I don't have access to.
Each tag must have different values in the xtag fields.
Code:
Tfred=Record
  num: integer;
  wp: byte;
  st: string;
end;

xtag: Tfred;

for i:=0 to 27 do
  sprite[i].tag:=xtag;
 

I would say that the Record construct is a bit out of date. While records still work for backwards compatibility, objects provide much more functionality.

Here is a working unit to show the way I would probably do it (based on what you have posted):
Code:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TSprite = class(TObject) // Don't know what a "sprite" is, but it has a tag property
  private
    FTag: integer;
  public
    property Tag:integer read FTag write FTag;
  end;

  TFred = class(TObject)
  private
    num: integer;
    wp: byte;
    st: string;
  public
    constructor Create( ANumber:integer; AByte:byte; AString:string );
  end;

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  sprite: array[0..27] of TSprite;

implementation

{$R *.dfm}

{ On create, extend all sprites with a TFred via the tag property.}
procedure TForm1.FormCreate(Sender: TObject);
var
  i:integer;
begin
  for i:=0 to 27 do
    Sprite[i]    := TSprite.Create;
  // Each sprite has custom "Fred" data...
  sprite[0].tag := Integer(TFred.Create( 1001, 42, 'This is 1001-42'));
  sprite[1].tag := Integer(TFred.Create( 1002, 43, 'This is 1002-43'));
  sprite[2].tag := Integer(TFred.Create( 1003, 44, 'This is 1003-44'));
  sprite[3].tag := Integer(TFred.Create( 1004, 45, 'This is 1004-45'));
  // etc.
  ShowMessage( 'Data from sprite[2]: ' + TFred(sprite[2].tag).st );
end;

{ On destroy, free all TFred and sprite objects. }
procedure TForm1.FormDestroy(Sender: TObject);
var
  i:integer;
begin
  for i := 0 to 27 do
    begin
      TFred(sprite[i].Tag).Free;
      sprite[i].Free;
    end;
end;


{ TFred }

constructor TFred.Create(ANumber: integer; AByte: byte; AString: string);
begin
  num := ANumber;
  wp  := AByte;
  st  := AString;
end;

end.
 
Thank you Zathras
Problem solved! I take in what you say about records.
I think my fear is of using a sledgehammer (in memory terms) to crack a nut. My feeling was that to create an object as you have done for what appears? to be a small job is expensive. I don't know what kind of overhead there really is, it just feels that way.
However, the solution is perfect and is now implemented and works just fine. I will be a little more liberal in my thinking from now on.
Great, thanks.
 
You might want to experiment with creating a descendant of your sprite object that adds the properties you need. Then do all of your work with the descendent type.

Something like this:
Code:
unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TSprite = class(TObject) // Don't know what a "sprite" is
  private
  public
  end;

  TFredSprite = class(TSprite)
  private
    Fwp: byte;
    Fnum: integer;
    Fst: string;
    procedure Setnum(const Value: integer);
    procedure Setwp(const Value: byte);
    procedure Setst(const Value: string);
    procedure InitFredData( ANum:integer; Awp:byte; Ast:string );
  public
    property num:integer read Fnum write Setnum;
    property wp:byte     read Fwp  write Setwp;
    property st: string  read Fst  write Setst;
  end;

  TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  sprite: array[0..27] of TFredSprite;

implementation

{$R *.dfm}

{ On create, extend all sprites with  Fred data.}
procedure TForm1.FormCreate(Sender: TObject);
var
  i:integer;
begin
  for i:=0 to 27 do
    Sprite[i]    := TFredSprite.Create;
  // Each sprite has custom "Fred" data...
  sprite[0].InitFredData(1001, 42, 'This is 1001-42');
  sprite[1].InitFredData(1002, 43, 'This is 1002-43');
  sprite[2].InitFredData(1003, 44, 'This is 1003-44');
  sprite[3].InitFredData(1004, 45, 'This is 1004-45');
  // etc.
  ShowMessage( 'Data from sprite[2]: ' + sprite[2].st );
end;

{ On destroy, free all TFredSprite objects. }
procedure TForm1.FormDestroy(Sender: TObject);
var
  i:integer;
begin
  for i := 0 to 27 do
    sprite[i].Free;
end;


{ TFred }


{ TFredSprite }

procedure TFredSprite.InitFredData(ANum: integer; Awp: byte; Ast: string);
begin
  num := ANum;
  wp  := Awp;
  st  := Ast;
end;

procedure TFredSprite.Setnum(const Value: integer);
begin
  Fnum := Value;
end;

procedure TFredSprite.Setst(const Value: string);
begin
  Fst := Value;
end;

procedure TFredSprite.Setwp(const Value: byte);
begin
  Fwp := Value;
end;

end.
I didn't want to spring this on you at first. I needed to wean you away from records. Walk before running.

 
Thanks again Zathras for your time.
I did go through this phase (as you suggest), being the simplest and most elegant but as noted in one of my posts the sprites are generated internally by another object which passes information (a lot) from itself to the sprites as they are generated (I don't have the source of these factories).

This should not matter much and it did work, but I had to add the new sprite (my descendant) to (I presume) a TObjectList descendant of which I also don't have source (I don't know what goes on in there).

When I tried to typecast my sprite back it recognised the new type but not the new properties (either being, it said, undefined, or on another occasion, incorrect typecast). The new properites were visible and accessible before placing in the list.
I didn't understand why and so tried the latest method with your help, using tag (quick and dirty?).

I tried recreating the factory but it was too dificult because there are several variations due to different sprite types. (Sprites are essentially moveable icons as used in say games, planning or demonstration applications).
 

Ok. Thought it might be something like that. I just didn't want this thread to end without a mention of the sub-classing technique in case anyone else can benefit from your experience.

Thanks for posting back. Glad you got it sorted.

 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top