I need to write a TQuery descendant with an override on onBeforePost event where I should check the state if its dsInsert or dsEdit or not... and allow or not the post to proceed, but I need someone with experience with custom components to double-check it.
It's been long since I created my components and I'm a bit rusty. Can you take a look at what I got and tell me if I am doing it right?
Here is my code for the component
unit MxQuery;
interface
uses
SysUtils, Classes, DB, DBTables;
type
TMxQuery = class(TQuery)
procedure DoBeforePost; override;
private
{ Private declarations }
protected
{ Protected declarations }
public
{ Public declarations }
published
{ Published declarations }
constructor Create(AOwner:TComponent); override;
end;
procedure Register;
implementation
constructor TMxQuery.Create(AOwner:Tcomponent);
begin
inherited create(AOwner);
end;
procedure Register;
begin
RegisterComponents('Samples', [TMxQuery]);
end;
procedure TMxQuery.DoBeforePost;
begin
case self.DataSource.State of
dsEdit,dsInsert:
begin
//Do nothing or other stuff
end;
else
begin
self.DataSource.DataSet.Cancel;
Abort;
end;
end;
inherited;
end;
end.
Thanks
Imho, this question fits https://codereview.stackexchange.com/ much better.
Anyway, let me point something out:
Your code should be working.
As #SirRufo said, you unnecessarily raised visibility of method DoBeforePost to published. Look for this this method in declaration TQuery or one of its ancestors. Override the method with the same visibility found there.
Constructor TMxQuery.Create is not needed, as it does not add anything.
Related
I have an interface IComm declaring a routine SetMonitorLogLevel():
unit IFaceComm;
interface
type
TMonitorLogLevel = (mllOnlyImportant, mllAll);
IComm = Interface(IInterface)
procedure SetMonitorLogLevel(LogLevel: TMonitorLogLevel);
end;
end.
The interface is implemented by 2 Forms, which are similar to each other, frmBarComm and frmFooComm, that look like this:
TfrmBarComm = class(TForm, IFaceComm.IComm)
cboDebugLevel: TComboBox;
private
procedure SetMonitorLogLevel(LogLevel: IFaceComm.TMonitorLogLevel);
end;
Note that the 2 Forms have a lot of components in common, such as cboDebugLevel, but also can have components the other doesn't.
Both Forms implement IComm.SetMonitorLogLevel() in exactly the same way:
procedure TfrmBarComm.SetMonitorLogLevel(LogLevel: IFaceComm.TMonitorLogLevel);
begin
case LogLevel of
IFaceComm.TMonitorLogLevel.mllOnlyImportant:
Self.cboDebugLevel.ItemIndex := 0;
IFaceComm.TMonitorLogLevel.mllAll:
Self.cboDebugLevel.ItemIndex := 1;
end;
end;
How do I avoid violating the Don't Repeat Yourself (DRY) principle? I'm faced with this issue quite often, and it's particularly ugly when the copy-pasted routines are much bigger than the simple example I shown above.
The usual way to deal with this is to create another class which implements the interface. It might look like this:
type
TComboBoxCommImplementor = class(TInterfacedObject, IFaceComm.IComm)
private
FDebugLevel: TComboBox;
public
constructor Create(DebugLevel: TComboBox);
procedure SetMonitorLogLevel(LogLevel: TMonitorLogLevel);
end;
constructor TComboBoxCommImplementor.Create(DebugLevel: TComboBox);
begin
inherited Create;
FDebugLevel := DebugLevel;
end;
procedure TComboBoxCommImplementor.SetMonitorLogLevel(
LogLevel: IFaceComm.TMonitorLogLevel);
begin
case LogLevel of
IFaceComm.TMonitorLogLevel.mllOnlyImportant:
FDebugLevel.ItemIndex := 0;
IFaceComm.TMonitorLogLevel.mllAll:
FDebugLevel.ItemIndex := 1;
end;
end;
Then in your form implement the interface using delegation:
type
TfrmBarComm = class(TForm, IFaceComm.IComm)
cboDebugLevel: TComboBox;
private
FComm: IFaceComm.IComm;
property Comm: IFaceComm.IComm read FComm implements IFaceComm.IComm
public
constructor Create(AOwner: TComponent); override;
end;
constructor TfrmBarComm.Create(AOwner: TComponent);
begin
inherited;
FComm := TComboBoxCommImplementor.Create(cboDebugLevel);
end;
Create a frame that owns the components which are used on both forms.
The frame implements IComm. Both forms using the frame and both forms implement IComm.
The frame is accessible as property that delegates the interface implementation.
It looks like this:
type TfrmBarComm = class(TForm)
FFrameComm: TFrameComm;
public
property FrameComm: TFrameComm read FFrameComm implements IComm;
end;
I have a Delphi XE+ application with 3 forms, 2 of them created dynamically, like so:
form_main is triggering form_equip
form_equip is triggering form_certif
form_main -> form_equip -> form_certif
1'st: Open form_equip
procedure Tform_main.button_equip_addClick(Sender: TObject);
var
form_equip: Tform_equip;
begin
form_equip:= Tform_equip.Create(Self);
form_equip.equip_id:= 0;
form_equip.ShowModal;
FreeAndNil(form_equip);
end;
On form_equip I have a public procedure has_changes
2'nd: Open form_certif
procedure Tform_equip.button_certif_addClick(Sender: TObject);
var
form_certif: Tform_certif;
begin
form_certif:= Tform_certif.Create(Self);
form_certif.index:= 0;
form_certif.ShowModal;
FreeAndNil(form_certif);
end;
Now, when I press OK button from form_certif
procedure Tform_certif.button_okClick(Sender: TObject);
begin
//do something...
form_equip.has_changes; //this public procedure from form_equip is not visible because form was created as local var on form_main
end;
The question is, how can I transmit the sender/parent name to form_certif so can I see the public procedures and variables from form_equip?
A simple way is to declare inside unit_equip as global:
var
form_equip: Tform_equip
but I avoid to do this because form_equip is made to be opened dynamically in multiple windows with different names...
Pass all needed information from form_equip to form_certif. That way form_certif is decoupled from any dependence of form_equip.
procedure Tform_equip.button_certif_addClick(Sender: TObject);
var
form_certif: Tform_certif;
begin
form_certif:= Tform_certif.Create(nil);
try
form_certif.index:= 0;
// Pass all other needed variable values to form_certif
// including callback methods
form_certif.Has_Changes_Method := Self.Has_Changes();
if form_certif.ShowModal = mrOk then
begin
// take care of changes
end;
finally
FreeAndNil(form_certif);
end;
end;
And this is how it would look in the form_certif unit:
type
THas_Changes_Method = procedure of Object;
TForm_Certif = class(TForm)
...
private
FIndex: Integer;
FHasChanges: THas_Changes_Method;
public
property Index: Integer read FIndex write FIndex;
property Has_Changes_Method: THas_Changes_Method read fHasChanges write fHasChanges;
end;
Pass the information as a parameter in the constructor. Declare the constructor like this:
constructor Create(AOwner: TComponent; const ParentName: string);
In the implementation of the constructor, make a note of the name that was passed.
Since you are creating forms in code, you can add custom constructor to the form and pass other form as parameter.
Tform_certif = class(TForm)
...
protected
form_equip: Tform_equip;
public
constructor Create(AOwner: TComponent; Aform_equip: Tform_equip); reintroduce;
end;
constructor Tform_certif.Create(AOwner: TComponent; Aform_equip: Tform_equip);
begin
inherited Create(AOwner);
form_equip := Aform_equip;
end;
So now you can call form_equip.has_changes, because it is a field that you have initialized during construction of your Tform_certif form and it points to particular instance of Tform_equip that created this particular instance of Tform_certif.
procedure Tform_certif.button_okClick(Sender: TObject);
begin
//do something...
// test whether form_equip is assigned to avoid AV by calling methods on nil object
if Assigned(form_equip) then form_equip.has_changes;
end;
And to create your Tform_certif you would use following code
procedure Tform_equip.button_certif_addClick(Sender: TObject);
var
form_certif: Tform_certif;
begin
form_certif:= Tform_certif.Create(Self, Self);
form_certif.index:= 0;
form_certif.ShowModal;
FreeAndNil(form_certif);
end;
There is also variation of above constructor code, where you only need to send one parameter and then test in constructor whether AOwner it is of Tform_equip type and you don't need to change code in button_certif_addClick for using that kind of solution.
Tform_certif = class(TForm)
...
protected
form_equip: Tform_equip;
public
constructor Create(AOwner: TComponent); override;
end;
constructor Tform_certif.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
if AOwner is Tform_equip then form_equip := Tform_equip(AOwner);
end;
I have created a component with TFrame as ancestor with the following code:
type
TCHAdvFrame = class(TFrame)
private
{ Private declarations }
FOnShow : TNotifyEvent;
FOnCreate : TNotifyEvent;
protected
procedure CMShowingChanged(var M: TMessage); message CM_SHOWINGCHANGED;
public
{ Public declarations }
constructor Create(AOwner: TComponent) ; override;
published
property OnShow : TNotifyEvent read FOnShow write FOnShow;
property OnCreate : TNotifyEvent read FOnCreate write FOnCreate;
end;
implementation
{$R *.dfm}
{ TCHAdvFrame }
procedure TCHAdvFrame.CMShowingChanged(var M: TMessage);
begin
inherited;
if Assigned(OnShow) then
begin
ShowMessage('onShow');
OnShow(self);
end;
end;
constructor TCHAdvFrame.Create(AOwner: TComponent);
begin
ShowMessage('OnCreate1');
inherited ;
ShowMessage('OnCreate2');
if Assigned(OnCreate) then
begin
ShowMessage('OnCreate3');
OnCreate(self);
end;
I have registered the new component and did some tests. ShowMessage('OnCreate1'); and ShowMessage('OnCreate2'); are correctly executed but not ShowMessage('OnCreate3');
This prevents to add code during the implementation of a new instance of TCHAdvFrame.
Why is it and how can I solve this ?
A frame is streamed in as part of its ultimate owner's constructor. Typically that will be a form. The form processes the .dfm file. It encounters new objects and creates them. Then it sets the properties of the newly created object. So, the frame's properties are set after its constructor returns.
This is the reason that TFrame does not have an OnCreate event. There is simply no way for the event to be fired because the event by necessity is assigned too late. The VCL designers omitted this event for the very same reason that led you to ask this question. So I do suspect that you likewise should not add this event.
How to solve this? Hard to say for sure unless we had a more detailed description of the problem. Perhaps you could override the frame's Loaded method to good effect. Or perhaps all you need to do is let consumers of your component override the constructor in their derived frames.
Related reading: http://delphi.about.com/od/delphitips2007/qt/tframe_oncreate.htm
On the new side of writing classes and have a little problem which I have tried researching but still no answer.
I want to create one instance of a class which creates multiple subclasses which creates subclasses of their own. The idea is to use code like this in main program:
procedure TForm1.Button1Click(Sender: TObject);
var
Temp : Integer;
begin
MainClass := TMainClass.Create(Form1);
Temp := MainClass.SubClass1.SubSubClass1.SomeValue;
end;
The main class looks like this and is created in seperate file:
TMainClass = class(TObject)
private
FSubClass1 : TSubClass1;
public
ValueFromAnySubClass : Integer;
property SubClass1 : TSubClass1 read FSubClass1 write FSubClass1;
procedure SetSomeValueFromMainClass(Value : Integer);
end;
...
...
...
procedure TMainClass.SetSomeValueFromMainClass(Value : Integer);
begin
ValueFromAnySubClass := Value;
end;
The sub class also in seperate file:
TSubClass1 = class(TObject)
private
FSubSubClass1 : TSubSubClass1;
public
property SubSubClass1 : TSubSubClass1 read FSubSubClass1 write FSubSubClass1;
end;
And now for the sub sub class also in seperate file:
TSubSubClass1 = class(TObject)
private
SomeValue : Integer;
function GetSomeValue : Integer;
procedure SetSomeValue(Value : Integer);
public
property SomeValue : Integer read GetSomeValue write SetSomeValue;
end;
...
...
...
procedure TSubSubClass1.SetSomeValue(Value : Integer);
begin
SetSomeValueFromMainClass(Value); <<< Error Here <<<
end;
How do I get to use the functions and procedures from the main class in my sub classes?
You don't need a subclass to use a function from another class. Also your sample code has not used subclasses at all. A proper subclass automatically has access to all public and proteced functions of its ancestors.
As David has already pointed out, there are serious flaws in your intended deisgn.
Furthermore, based on your comment:
The classes all perform vastly different functions but need to write data to a piece of hardware at the end of the day. The data is read from the hardware and kept in memory to work with until its written back to the hardware component once all work is completed. The procedure in the main class takes care of writing real time data to the hardware whenever it is required by any of the subclasses.
to David's answer: you don't need subclasses at all.
All you need is a public method on your hardware class. And for each instance of your other classes to have a reference to the correct instance of your hardware class.
type
THardwareDevice = class(TObject)
public
procedure WriteData(...);
end;
TOtherClass1 = class(TObject)
private
FDevice: THardwareDevice;
public
constructor Create(ADevice: THardwareDevice);
procedure DoSomething;
end;
constructor TOtherClass1.Create(ADevice: THardwareDevice);
begin
FDevice := ADevice;
end;
procedure TOtherClass1.DoSomething;
begin
//Do stuff, and maybe you need to tell the hardware to write data
FDevice.WriteData(...);
end;
//Now given the above you can get two distinct object instances to interact
//as follows. The idea can be extended to more "other class" types and instances.
begin
FPrimaryDevice := THardwareDevice.Create(...);
FObject1 := TOtherClass1.Create(FPrimaryDevice);
FObject1.DoSomething;
//NOTE: This approach allows extreme flexibility because you can easily
// reference different instances (objects) of the same hardware class.
FBackupDevice := THardwareDevice.Create(...);
FObject2 := TOtherClass1.Create(FBackupDevice);
FObject2.DoSomething;
...
end;
The design looks really poor. You surely don't want to have all these classes knowing all about each other.
And any time you see a line of code with more than one . operator you should ask yourself if the code is in the right class. Usually that indicates that the line of code that has multiple uses of . should be in one of the classes further down the chain.
However, if you want to call a method, you need an instance. You write:
procedure TSubSubClass1.SetSomeValue(Value : Integer);
begin
SetSomeValueFromMainClass(Value);
end;
And naturally this does not compile. Because SetSomeValueFromMainClass is not a method of TSubSubClass1. Rather SetSomeValueFromMainClass is a method of TMainClass. So, to call that method, you need an instance of TMainClass.
Which suggests that, if you really must do this, that you need to supply to each instance of TSubSubClass1 an instance of TMainClass. You might supply that in the constructor and make a note of the reference.
Of course, when you do this you now find that your classes are all coupled together with each other. At which point one might wonder whether or not they should be merged.
I'm not saying that merging these classes is the right design. I would not like to make any confident statement as to what the right design is. Perhaps what you need is an interface that promises to implement the setter as a means to decouple things. All I am really confident in saying is that your current design is not the right design.
As far as I know Subclass word is usually using in inheritance concept but the code you wrote are some compound classes. As you may see the constructor of many classes in Delphi have an argument which named AOwner that may be TComponent or TObject or ...
If you define the constructors of your TSubclass1 and TSubSubClass1 like as follow and Change the Owner of classes that you defined as properties to Self in set functions you may access to your TMainClass by typecasting the Owner property.
I changed your code a little to just work as you want, but I suggest change your design.
TSubSubClass1 = class(TObject)
private
FOwner: TObject;
function GetSomeValue:Integer;
procedure SetSomeValue(const Value: Integer);
procedure SetOwner(const Value: TObject);
public
constructor Create(AOwner:TObject);reintroduce;
property Owner:TObject read FOwner write SetOwner;
property SomeValue : Integer read GetSomeValue write SetSomeValue;
end;
TSubClass1 = class(TObject)
private
FSubSubClass1: TSubSubClass1;
FOwner:TObject;
procedure SetSubSubClass1(const Value: TSubSubClass1);
procedure SetOwner(const Value: TObject);
public
constructor Create(AOwner:TObject);reintroduce;
property Owner:TObject read FOwner write SetOwner;
property SubSubClass1 : TSubSubClass1 read FSubSubClass1 write SetSubSubClass1;
end;
TMainClass = class(TObject)
private
FSubClass1: TSubClass1;
procedure SetSubClass1(const Value: TSubClass1);
public
ValueFromAnySubClass : Integer;
constructor Create;
property SubClass1 : TSubClass1 read FSubClass1 write SetSubClass1;
procedure SetSomeValueFromMainClass(Value : Integer);
end;
implementation
{ TSubSubClass1 }
constructor TSubSubClass1.Create(AOwner: TObject);
begin
Owner:=AOwner;
end;
function TSubSubClass1.GetSomeValue: Integer;
begin
Result:=TMainClass(TSubClass1(Self.Owner).Owner).ValueFromAnySubClass;
end;
procedure TSubSubClass1.SetOwner(const Value: TObject);
begin
FOwner := Value;
end;
procedure TSubSubClass1.SetSomeValue(const Value: Integer);
begin
TMainClass(TSubClass1(Self.Owner).Owner).SetSomeValueFromMainClass(Value);
end;
{ TSubClass1 }
constructor TSubClass1.Create(AOwner: TObject);
begin
Owner:=AOwner;
FSubSubClass1:=TSubSubClass1.Create(Self);
end;
procedure TSubClass1.SetOwner(const Value: TObject);
begin
FOwner := Value;
end;
procedure TSubClass1.SetSubSubClass1(const Value: TSubSubClass1);
begin
FSubSubClass1 := Value;
FSubSubClass1.Owner:=Self;
end;
{ TMainClass }
constructor TMainClass.Create;
begin
FSubClass1:=TSubClass1.Create(Self);
end;
procedure TMainClass.SetSomeValueFromMainClass(Value: Integer);
begin
ValueFromAnySubClass := Value;
end;
procedure TMainClass.SetSubClass1(const Value: TSubClass1);
begin
FSubClass1 := Value;
FSubClass1.Owner:=Self;
end;
you must put the proper filename in uses part of implementation.
I have the following problem: I've got an entity class 'TEntity' and a mesh class 'TMesh' and TEntity needs to know when its element, (TMesh) is removed. Is there a possible working way I can call the TEntity method 'OnMeshRemove' from the TMesh destructor?
//uTEntity
interface
uses
uTMesh;
type
TEntity = class
Mesh : TMesh;
constructor Create(); overload;
procedure OnMeshRemove();
end;
implementation
constructor TEntity.Create();
begin
Mesh := TMesh.Create();
Mesh.EntityContainer := #self;
end;
procedure TEntity.OnMeshRemove();
begin
//Do stuff
end;
end.
//uTMesh
interface
type
TMesh = class
EntityContainer : Pointer;
destructor Remove();
end;
implementation
uses
uTEntity;
destructor TMesh.Remove();
var
PEntity : ^TEntity;
begin
PEntity := EntityContainer;
if Assigned( PEntity^ ) then
begin
PEntity^.OnMeshRemove();
end;
inherited Destroy();
end;
Example:
var
Ent : TEntity;
begin
Ent := TEntity.Create();
Ent.Mesh.Remove();
//I want Ent.OnMeshRemove to be called. In my example code, there is a pointer problem. I need to solve that. Thanks!
end;
PS: I don't want to have a TEntity procedure like TEntity.RemoveMesh();
All objects in Delphi are pointer type so no need to deference it. Here is a bit more simpler
type
TEntity = class
public
Mesh: TMesh;
constructor Create;
destructor Destroy; override;
end;
implementation
constructor TEntity.Create;
begin
inherited Create;
Mesh := TMesh.Create;
Mesh.EntityContainer := Self;
end;
procedure TEntity.Destroy;
begin
if Mesh <> nil then
begin
Mesh.EntityContainer := nil;
FreeAndNil(Mesh);
end;
inherited Destroy;
end;
//***************************************************
type
TMesh = class
EntityContainer: TObject;
destructor Destroy; override;
end;
implementation
uses
uTEntity;
destructor TMesh.Destroy;
begin
if (EntityContainer <> nil) and (TEntity(EntityContainer).Mesh = Self) then
TEntity(EntityContainer).Mesh := nil;
EntityContainer := nil;
inherited Destroy;
end;
Your TEntity instance should register itself with TMesh instance so that when TMesh instance is being freed, it will modify the TEntity instance about it.
If your classes are derived from TComponent class, then this mechanism is already implemented for you; each TComponent instance has a method called FreeNotification and a method called Notification. Any TComponent instance can register itself with the other component calling its FreeNotification method and passing itself as the parameter. Whenever a component is being destroyed, it will check the list of components registered for its free notification, and will invoke Notification method of each registered component. This way, the register component will be notified whenever the other component is about to be destroyed.
If one TComponent instance is the owner of the other (In your case, TEntity can be the owner of TMesh instance), then it will be notified automatically whenever TMesh instance is removed. All you need to do is to override its Notification method and do whatever you want to do inside that method.
If you do not want to derive your classes from TComponent class or for any reason do not want to use Delphi's implementation, you can implement the same behavior in your own classes. You need an internal list in your TMesh class which holds a list of classes which should be notified. You also need a method to register a class with your TMesh class, and eventually you need a method in your TEntity class which should be called by TMesh whenever it is being freed.
Here is a simple source code just for demonstrating the general idea. Take note that this sample code is not thread-safe, and might lack some other checks. I just wrote it fast to show you how to implement such an idea:
unit Unit1;
interface
uses
Classes, Generics.Collections;
type
TBaseClass = class
private
FNotificationList : TList<TBaseClass>;
protected
procedure Notify(AClass: TBaseClass); virtual;
public
procedure RegisterForNotification(AClass: TBaseClass);
procedure UnregisterNotification(AClass: TBaseClass);
constructor Create;
destructor Destroy; override;
end;
TMesh = class(TBaseClass)
end;
TEntity = class(TBaseClass)
private
FMesh : TMesh;
FOnMeshRemoved : TNotifyEvent;
procedure SetMesh(Value: TMesh);
protected
procedure Notify(AClass: TBaseClass); override;
procedure DoMeshRemoved; virtual;
public
constructor Create;
destructor Destroy; override;
property Mesh : TMesh read FMesh write SetMesh;
property OnMeshRemoved : TNotifyEvent read FOnMeshRemoved write FOnMeshRemoved;
end;
implementation
{ TBaseClass }
constructor TBaseClass.Create;
begin
inherited;
FNotificationList := TList<TBaseClass>.Create;
end;
destructor TBaseClass.Destroy;
var
AClass: TBaseClass;
begin
if Assigned(FNotificationList) then
begin
if (FNotificationList.Count > 0) then
for AClass in FNotificationList do
AClass.Notify(Self);
FNotificationList.Free;
FNotificationList := nil;
end;
inherited;
end;
procedure TBaseClass.Notify(AClass: TBaseClass);
begin
end;
procedure TBaseClass.RegisterForNotification(AClass: TBaseClass);
begin
if not Assigned(AClass) then
Exit;
if FNotificationList.IndexOf(AClass) < 0 then
FNotificationList.Add(AClass);
end;
procedure TBaseClass.UnregisterNotification(AClass: TBaseClass);
begin
if not Assigned(AClass) then
Exit;
if FNotificationList.IndexOf(AClass) >= 0 then
FNotificationList.Remove(AClass);
end;
{ TEntity }
constructor TEntity.Create;
begin
inherited;
end;
destructor TEntity.Destroy;
begin
if Assigned(FMesh) then
FMesh.UnregisterNotification(Self);
inherited;
end;
procedure TEntity.DoMeshRemoved;
begin
if Assigned(FOnMeshRemoved) then
FOnMeshRemoved(Self);
end;
procedure TEntity.Notify(AClass: TBaseClass);
begin
inherited;
FMesh := nil;
DoMeshRemoved;
end;
procedure TEntity.SetMesh(Value: TMesh);
begin
if Assigned(FMesh) then
begin
FMesh.UnregisterNotification(Self);
FMesh := nil;
end;
if Assigned(Value) then
begin
FMesh := Value;
FMesh.RegisterForNotification(Self);
end;
end;
end.
In this code, both TEntity and TMesh are derived from TBaseClass which provides notification mechanism. TEntity does not create any instance of TMesh initially, but you can assign a created TMesh instance to its Mesh property. Doing so will make TEntity to assign that value to its FMesh field, and call its RegisterForNotification class so that it can be notified if the mesh is being destroyed.
When the mesh is being destroyed, it iterates over all the objects registered themselves with it, and invokes their Notify method. Here it would be Notify method of TEntity class. Inside Notify method of TEntity, it first makes its FMesh field nil, because that object is being destroyed and there is no need to keep a reference of a dead object. It then calls DoMeshRemove method which is an event-invoker for OnMeshRemove event.
Edit: back behind a PC.
The classic way of maintaining lists of predetermined objects of a certain class is using TCollection/TCollectionItem.
TCollection/TCollectionItem are heavily used in Delphi (see this list).
They are lighter weight than TComponent (that automatically maintains Owner/Components/ComponentCount and has FreeNotification), as TCollectionItem and TCollection both descend from the TPersistent branch in stead of TComponent branch.
TCollection has a nice virtual Notify method:
procedure TCollection.Notify(Item: TCollectionItem; Action: TCollectionNotification);
begin
case Action of
cnAdded: Added(Item);
cnDeleting: Deleting(Item);
end;
end;
From Delphi 2009, you have generics, so then it can pay off big time to use TList (in your cast TList<TEntity>, as it contains this very nice Notify method and OnNotify event:
procedure TList<T>.Notify(const Item: T; Action: TCollectionNotification);
begin
if Assigned(FOnNotify) then
FOnNotify(Self, Item, Action);
end;
These two solutions work well if your TMesh is indeed a collection/list of TEntity.
If it TMesh is a non-list graph of TEntity, then it is better to descend both from TComponent like vcldeveloperlink text explained in his answer.
Andy Bulka has a nice blog post on the various ways of using lists and collections, including a well balanced view of TCollection/TCollectionItem usage.
--jeroen
Old answer (great iPad auto-complete bugs fixed):
Sorry for the short answer, as I am on the road only carrying a mobile device.
It looks like your mesh is a container for entities.
If so, then you should look into TCollection and TCollectionItem.
Derive your mesh from the former and your entity from the latter.
The delphi vcl source code contain many examples of these: fields/field or actions/action are good starters.