我想创建一个我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;
Run Code Online (Sandbox Code Playgroud)
现在我想将它存储在一个数组中.
arrSprites: array[0..1000] of TSprite;
Run Code Online (Sandbox Code Playgroud)
而现在的创作(我努力的部分)
这是我到目前为止:
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;
Run Code Online (Sandbox Code Playgroud)
那么这段代码应该做的是在一个名为fsbcanvas的滚动框内创建一个带有选择的图像.
为了清楚我要求创建一个实例的代码TSprite.
谢谢
当David Heffernan刚刚打败我时,我正在输入一个答案.还是在它的时候我想补充一下;
意识到在你的第一个代码示例中,您正在使用记录(TSprite)来保存对象(TImage).TImage实际上是一个可视组件,但最终它来自TObject.
一个记录是一样的,因为它没有被实例化,并可以随意复制大多数变量(如Integer).
一个对象然而是一个指向一个实例,并通过以下步骤必须创建/销毁
rec.Image := TImage.Create(nil);
// do other things..
rec.Image.Free;
Run Code Online (Sandbox Code Playgroud)
因此,如果操作不当,可能会导致内存泄漏或访问冲突错误.(例如在复制TSprite时...)在这种设置中有很多东西可能出错,因此我说;
一个简单的解决方案(如果你确实希望在TSprite中保留TImage的实例或指针引用)将使TSprite也成为一个对象.它可以通过使用它的构造函数和析构函数自动跟踪创建/销毁:
TSpriteObject = class(TObject)
public
Image : TImage;
constructor Create;
destructor Destroy; override;
end;
Run Code Online (Sandbox Code Playgroud)
及其实施:
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;
Run Code Online (Sandbox Code Playgroud)
然后,您可以让TObjectList跟踪许多TSprite实例,并在清除或销毁列表时销毁任何TSprite(它会破坏其TImage).
(这是我第一次尝试stackoverflow帖子,请在我发现我在这里做错的时候请耐心等待)
不需要创建记录.它们是值类型,您应该以与考虑其他值类型相同的方式来考虑它们,例如Integer.声明一个局部变量或一个值类型的类字段,这就是你需要做的.类似地,常量大小的数组是值类型.
所以,你的问题的答案是,arrSprites不需要任何特殊的分配.需要分配和初始化的是记录的内容.因此,如果记录中的任何字段是类实例,那么它们需要实例化.所以,考虑这个记录:
type
TMyRecord = record
i: Integer;
obj: TObject;
end;
Run Code Online (Sandbox Code Playgroud)
你可以这样声明一个:
var
rec: TMyRecord;
Run Code Online (Sandbox Code Playgroud)
并且记录本身已分配.但是你需要初始化它的成员:
rec.i := 42; // or some other initial value
rec.obj := TObject.Create; // instantiate the object
Run Code Online (Sandbox Code Playgroud)
当你完成记录后,你需要销毁这个对象.
rec.obj.Free;
Run Code Online (Sandbox Code Playgroud)
这很容易出错,因此通常您的记录应该只包含值类型或托管类型(例如字符串,接口,动态数组等)
现在,我不知道你的代码是什么,问题是什么,但我怀疑你的记录有一些类实例.这立即使记录成为一种可疑的数据结构选择.我将这些包含在一个具有构造函数和析构函数的类中,该类管理对象的生命周期.
而且我也避免使用恒定长度的数组.他们非常不灵活.相反,我建议你将精灵对象保存在通用列表中TList<T>.或者,甚至可能更好,TObjectList<T>这样你就可以让列表照顾其成员的生命周期.