0

実行時に呼び出すレコードを作成したいTSprite

TSpriteは、私が作成しているレベルエディタで使用している画像と8つの選択ポイントです。

type 
  TSprite = record
    Image: TImage;
    Selection: TSelection;
    SelectionPointTL: TSelectionPoint; // top-left
    SelectionPointTM: TSelectionPoint; // top-middle
    SelectionPointTR: TSelectionPoint; // top-right
    SelectionPointML: TSelectionPoint; // middle-left
    SelectionPointMR: TSelectionPoint; // middle-right
    SelectionPointBL: TSelectionPoint; // bottom-left
    SelectionPointBM: TSelectionPoint; // bottom-middle
    SelectionPointBR: TSelectionPoint; // bottom-right
  end;

今、私はそれを配列に保存したいと思います。

arrSprites: array[0..1000] of TSprite;

そして今、創造(私が苦労している部分)

これは私がこれまでに持っているものです:

arrSprites[i].Image.Position.X := frmMainUI.CurrentMouseX;
arrSprites[i].Image.Position.Y := frmMainUI.CurrentMouseY;
arrSprites[i].Image.Bitmap.LoadFromFile('1.png');
arrSprites[i].Image.Visible := True;
arrSprites[i].Image.WrapMode := TImageWrapMode.iwStretch;

したがって、このコードが行うことになっているのは、名前がfsbcanvasであるスクロールボックス内に選択範囲を含む画像を作成することです。

明確にするために、のインスタンスを作成するコードを求めていますTSprite

ありがとう

4

3 に答える 3

9

レコードを作成する必要はありません。それらは値型であり、他の値型について考えるのと同じように考える必要がありますInteger。値型であるローカル変数またはクラスフィールドを宣言し、それがあなたがする必要があるすべてです。同様に、一定サイズの配列は値型です。

したがって、あなたの質問に対する答えは、arrSprites特別な割り当てを必要としないということです。割り当てと初期化が必要なのは、レコードの内容です。したがって、レコード内のフィールドのいずれかがクラスインスタンスである場合は、インスタンス化する必要があります。したがって、このレコードを検討してください。

type
  TMyRecord = record
    i: Integer;
    obj: TObject;
  end;

次のように宣言できます。

var
  rec: TMyRecord;

レコード自体が割り当てられます。ただし、そのメンバーを初期化する必要があります。

rec.i := 42; // or some other initial value
rec.obj := TObject.Create; // instantiate the object

そして、レコードが完成したら、オブジェクトを破棄する必要があります。

rec.obj.Free;

これは間違いやすいため、通常、レコードには値型または管理対象型(文字列、インターフェイス、動的配列など)のみを含める必要があります。

さて、質問の内容からあなたのコードが何であるかはわかりませんが、あなたのレコードにはいくつかのクラスインスタンスが含まれていると思われます。これはすぐにデータ構造の疑わしい選択を記録します。これらは、オブジェクトの存続期間を管理するコンストラクタとデストラクタを持つクラスに保持します。

また、一定の長さの配列を使用することも避けたいと思います。彼らは非常に柔軟性がありません。代わりに、スプライトオブジェクトを汎用リストに保持することをお勧めしますTList<T>。または、おそらくさらに良いTObjectList<T>方法で、リストにそのメンバーの存続期間を管理させることができます。

于 2013-02-21T15:32:42.017 に答える
9

David Heffernanが私を打ち負かしたので、私は答えを入力していました。それでも、追加したいと思います。

最初のコード例では、レコード(TSprite)を使用してオブジェクト(TImage)を保持していることを認識してください。TImageは実際には視覚的なコンポーネントですが、最終的にはTObjectの子孫です。

レコードは、インスタンス化する必要がなく、自由にコピーできるという点で、ほとんどの変数(整数など)に似ています。

ただし、オブジェクトはインスタンスへのポインタであり、次の手順に従って作成/破棄する必要があります

rec.Image := TImage.Create(nil);
// do other things..
rec.Image.Free;

したがって、適切に行わないと、メモリリークやアクセス違反エラーが発生する可能性があります。(たとえば、TSpriteをコピーしているとき..)このセットアップではうまくいかないことがたくさんあるので、私は言います。

レコードでオブジェクトを使用すると、注意が必要になる場合があります。オブジェクトをオブジェクトに保持することを検討してください。

簡単な解決策(実際にTSprite内にTImageのインスタンスまたはポインター参照を保持したい場合)は、TSpriteもオブジェクトにすることです。コンストラクタとデストラクタを使用して、自動的に作成/破棄を追跡できます。

TSpriteObject = class(TObject)
public
  Image : TImage;

  constructor Create;
  destructor  Destroy; override;
end;

およびその実装:

constructor TSpriteObject.Create;
begin
  Image := TImage.Create(nil);
  // ^ TImage is a component and expects an Owner component that would also
  //   destroy it, so we use a nil value to disable that behavior.
end;

destructor TSpriteObject.Destroy;
begin
  Image.Free;
end;

次に、TObjectListにTSpriteの多くのインスタンスを追跡させることができ、リストがクリアまたは破棄されると、TSprite(TImageを破棄する)を破棄します。

(これは私の初めてのstackoverflowポストの試みです、私がここで間違っていることを見つけている間、私に耐えてください)

于 2013-02-21T15:51:57.057 に答える
1

David Heffernanが言ったように、この状況ではクラスがより良いデータ構造である可能性があります。ただし、代わりにレコードを使用することにした場合は、レコードでメソッドを宣言して、パーツのインスタンス化と破棄をリファクタリングできます。

type
  TSprite = record
    Image: TImage;
    Selection: TSelection;
    SelectionPointTL: TSelectionPoint; // top-left
    SelectionPointTM: TSelectionPoint; // top-middle
    SelectionPointTR: TSelectionPoint; // top-right
    SelectionPointML: TSelectionPoint; // middle-left
    SelectionPointMR: TSelectionPoint; // middle-right
    SelectionPointBL: TSelectionPoint; // bottom-left
    SelectionPointBM: TSelectionPoint; // bottom-middle
    SelectionPointBR: TSelectionPoint; // bottom-right
    procedure Create(aImageOwner: TComponent);
    procedure Destroy;
  end;

{ TSprite }

procedure TSprite.Create(aImageOwner: TComponent);
begin
  Image := TImage.Create(aImageOwner);
end;

procedure TSprite.Destroy;

begin
  Image.Free;
end;

// ...

var
  Rec: TSprite;
begin
  Rec.Create(Form1);

  // ...

  Rec.Destroy;
end;

これは実際のクラスのインスタンス化ではないため、そのようRec := TSprite.Create(Form1);に定義して実装する場合を除いて、意味がないことに注意してくださいTSprite.Create

于 2013-02-22T09:43:23.243 に答える