Я создаю пользовательский элемент управления OpenGL, который состоит из списка элементов, где каждый элемент может быть другим классом, но унаследован от определенного общего типа класса. Я не знаю, как это сделать таким образом, чтобы я мог выполнять цикл через эти элементы и выполнять определенные действия, которые, как ожидается, будут переопределены в унаследованных классах.Список объектов, унаследованных от общего класса, вызывающего переопределенную процедуру?
Чтобы быть более конкретным, это список визуальных объектов, предназначенных для рисования на холсте. У меня есть общий класс TGLItem
, который используется для создания нескольких классов наследования. Например, TGLCar
наследуется от TGLItem
и добавляется в список TGLItems
. Этот класс настраиваемого списка является частью элемента управления.
Когда элемент управления рисует, он выполняет цикл по этому списку элементов и вызывает процедуру Draw
каждого элемента. Draw
предназначен для переопределения классами наследования, где происходит фактический рисунок элемента. Таким образом, реальная работа выполняется с помощью процедуры Draw
, которая реализована в классе TGLCar
, но она вызывается только из основного элемента управления.
Основной элемент управления (TGLImage
) не должен знать, что такое фактический унаследованный элемент, но иметь возможность вызвать его процедуру Draw
, ожидая, что она будет обращена к OpenGL.
Как структурировать этот список элементов и базу позиций таким образом, чтобы можно было разместить этот сценарий? Вот то, что я до сих пор:
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;
реализации ...
{ 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;
OpenGL ее часть не обязательно актуально в этом случае, я просто хотел объяснить немного подробнее о том, что это предназначен для того, чтобы иметь представление о том, как я ожидаю, что это сработает.
У меня также есть идея передать объект списка TGLItems
каждому отдельному элементу в его конструкторе, и каждый элемент регистрирует себя в списке элементов. В этом случае список элементов не будет иметь никакой процедуры добавления, и мне, вероятно, даже не понадобится отдельный объект списка. Я просто уверен, что в этом должен быть какой-то большой трюк, который мне не хватает, и я открыт для любых масштабных изменений в структуре, чтобы более эффективно адаптироваться к этому.
PS - Прибегая к библиотеке третьей стороной не может быть ответа, так как этот проект на самом деле имел в виду для меня изучите аспекты Delphi на более низком уровне. Поэтому такие вещи, как GLScene, которые у меня уже есть, не будут ответом. –