I'm building a custom OpenGL control which consists of a list of items where each item may be a different class, but inherited from a certain common class type. I don't know how to do this in a way where I can do a loop through these items and perform certain actions which are expected to be overridden in the inherited classes.
To be more specific, this is a list of visual objects which are meant to be drawn to a canvas. I have a common class TGLItem
which is used to create a number of inheritance classes. For example, TGLCar
is inherited from TGLItem
and is added to the list TGLItems
. This custom list class is part of the control.
When the control draws, it does a loop through this item list and calls the Draw
procedure of each item. Draw
is intended to be overridden by the inheritance classes where the actual drawing of the item occurs. So the real work is done from the Draw
procedure which is implemented in the TGLCar
class but it is only called from the main control.
The main control (TGLImage
) shall have no knowledge of what the actual inherited item is, but be able to call its Draw
procedure expecting it to draw to OpenGL.
How do I structure this item list and item base in a way to accommodate for this scenario? Here's what I have so far:
TGLItems = class(TPersistent)
private
FItems: TList;
function GetItem(Index: Integer): TGLItem;
procedure SetItem(Index: Integer; const Value: TGLItem);
public
constructor Create;
destructor Destroy; override;
procedure Add(AItem: TGLItem);
function Count: Integer;
property Items[Index: Integer]: TGLItem read GetItem write SetItem; default;
end;
TGLItem = class(TPersistent)
private
FPosition: TGLPosition;
FDimensions: TGLDimensions;
FOwner: TGLItems;
FItemClass: TGLItemClass;
procedure PositionChanged(Sender: TObject);
procedure DimensionsChanged(Sender: TObject);
procedure SetPosition(const Value: TGLPosition);
procedure SetDimensions(const Value: TGLDimensions);
public
constructor Create(Owner: TGLItems);
destructor Destroy; override;
procedure Draw;
property Owner: TGLItems read FOwner;
property ItemClass: TGLItemClass read FItemClass;
published
property Position: TGLPosition read FPosition write SetPosition;
property Dimensions: TGLDimensions read FDimensions write SetDimensions;
end;
implementation...
{ TGLItem }
constructor TGLItem.Create;
begin
FPosition:= TGLPosition.Create;
FPosition.OnChange:= PositionChanged;
FDimensions:= TGLDimensions.Create;
FDimensions.OnChange:= DimensionsChanged;
end;
destructor TGLItem.Destroy;
begin
FPosition.Free;
FDimensions.Free;
inherited;
end;
procedure TGLItem.DimensionsChanged(Sender: TObject);
begin
end;
procedure TGLItem.Draw;
begin
//Draw to gl scene
end;
procedure TGLItem.PositionChanged(Sender: TObject);
begin
end;
procedure TGLItem.SetDimensions(const Value: TGLDimensions);
begin
FDimensions.Assign(Value);
end;
procedure TGLItem.SetPosition(const Value: TGLPosition);
begin
FPosition.Assign(Value);
end;
{ TGLItems }
procedure TGLItems.Add(AItem: TGLItem);
begin
FItems.Add(AItem);
//Expects objects to be created and maintained elsewhere
//This list object will not create/destroy any items
end;
function TGLItems.Count: Integer;
begin
Result:= FItems.Count;
end;
constructor TGLItems.Create;
begin
FItems:= TList.Create;
end;
destructor TGLItems.Destroy;
begin
FItems.Free;
inherited;
end;
function TGLItems.GetItem(Index: Integer): TGLItem;
begin
Result:= TGLItem(FItems[Index]);
end;
procedure TGLItems.SetItem(Index: Integer; const Value: TGLItem);
begin
TGLItem(FItems[Index]).Assign(Value);
end;
The OpenGL part of it isn't necessarily relevant in this scenario, I just wanted to explain a little detail of what this is intended for to have an idea of how I expect this to work.
I also have the idea of passing the TGLItems
list object to each individual item in its constructor, and having each item register its self in the item list. In this case, the item list wouldn't have any add procedure, and I probably wouldn't even need a separate list object. I'm just sure there should be some big trick to this that I'm missing, and I'm open to any large scale changes to the structure to more efficiently accommodate for this.