各アイテムが異なるクラスである可能性があるが、特定の共通クラスタイプから継承されているアイテムのリストで構成されるカスタム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
また、コンストラクター内の個々のアイテムにリストオブジェクトを渡し、各アイテムにアイテムリストに自分自身を登録させるというアイデアもあります。この場合、アイテムリストには追加プロシージャがなく、おそらく別のリストオブジェクトも必要ありません。これには、私が見逃している大きなトリックがあるはずだと確信しています。これに効率的に対応するために、構造に大規模な変更を加えることもできます。