我目前在组件属性的类型转换方面遇到了严重的问题。
在我的表单上,我有一个叫做“场景”的TPanel。同样在表单上,我有一个创建TSelection
的按钮,在TSelection
内创建TImage
,然后将图片加载到该TImage中。 TSelection的名称通过称为“ImgObjName”的TEdit分配。然后它将此名称写入inifile。 TSelection的事件被分配给代码中其他位置的过程。如您所知,TSelection组件可以在运行时移动(并调整大小)。当TSelection开启时,TImage关闭了HitTest。
上面的工作正如我所希望的那样,但下一部分是我被困的地方。本质上,在计时器上,我想将每个子组件的一些属性写入TMemIniFile。有两种方式我愿意这样做;
1)写下每个孩子的属性以分开TMemInifiles
2)将每个子项的属性写入单个TMemIniFile,但使section
标识该部分中的值与哪个组件相关。
我尝试了一些不同的方法,但所有这些方法都给我带来了一些重大问题(通常是“索引越界”)。
我目前的方法是这样的;
ChgPos
是一个全局布尔变量,当其中一个TSelection对象上的mousedown事件触发时为TRUE,而当触发MouseUp事件时为FALSE。这个布尔过程非常适合这些目的,因此不需要进行任何更改。
TimerBar
是在设计时创建的TTrackBar
。这是基于计时器的价值变化。
AnimIni
是之前在代码中分配的TMemIniFile。为此,我将其设置为不释放文件(因为没有访问冲突)。
var
i: Integer;
PosX, PosY: Integer;
begin
for i := 0 to Scene.ChildrenCount - 1 do
begin
if Scene.Components[i] is TSelection then
begin
PosX := AnimIni.ReadInteger(IntToStr(Round(TimerBar.Value)) + '_Object' +
IntToStr(i), 'PosX', PosX);
PosY := AnimIni.ReadInteger(IntToStr(Round(TimerBar.Value)) + '_Object' +
IntToStr(i), 'PosY', PosY);
end;
end;
if ChgPos = False then
begin
if Scene.Components[i] is TSelection then
begin
(Scene.Components[i] as TSelection).Position.X := PosX;
(Scene.Components[i] as TSelection).Position.Y := PosY;
end;
end
else if ChgPos = True then
begin
AnimIni.WriteInteger(IntToStr(Round(TimerBar.Value)) + '_Object' +
IntToStr(i), 'PosX', Round((Scene.Children[i] as TSelection).Position.X));
AnimIni.WriteInteger(IntToStr(Round(TimerBar.Value)) + '_Object' +
IntToStr(i), 'PosY', Round((Scene.Children[i] as TSelection).Position.Y));
end;
end;
我正在努力弄清楚要去哪里。我正在使用它获得“索引超出范围”错误。我还需要保存TImage组件属性(特别是父和Bitmap位置,但我觉得让代码至少使用一个组件对我来说很重要。)
我对于类型转换有点新手(因为我以前的所有项目都不需要它),但到目前为止,我所有的经验都取得了成功。只是在这种特殊情况下,事实证明,如果没有一些帮助,我会变得更加复杂。
我确实尝试了WriteComponent
和ReadComponent
并使用多个文件实时传输与TimerBar值相关的数据但是对于我想要实现的内容来说太慢了(特别是在写入时)功能)。 inifile方法确实可以在我之前的测试中运行,但它实际上是在运行时创建的多个组件的类型转换,我遇到了问题。
任何人都可以对潜在的解决方案或我应该进入的方向有所了解吗?
答案 0 :(得分:6)
Components
属性上使用该索引,而是使用Children
属性。 (我假设您的代码已编译且XE2具有Children
属性,否则我认为您的意思是Controls
和ControlCount
)。就像LU RD已经评论过的那样,你在for循环之外使用for循环变量i
。我相信你想要它。编译器也会警告您:
循环变量'i'可能在循环
之后未定义
始终确保你没有!编译器错误,警告和提示。
ChgPos
为假时加载MemIniFile中的设置。没有给出任何保证,但我认为例程应该如下(包括一些语法改进):
var
i: Integer;
Selection: TSelection;
PosX, PosY: Integer;
begin
for i := 0 to Scene.ChildrenCount - 1 do
if Scene.Children[i] is TSelection then
begin
Selection := Scene.Children[i] as TSelection;
if ChgPos then
begin
AnimIni.WriteInteger(IntToStr(Round(TimerBar.Value)) + '_Object' +
IntToStr(i), 'PosX', Round(Selection.Position.X));
AnimIni.WriteInteger(IntToStr(Round(TimerBar.Value)) + '_Object' +
IntToStr(i), 'PosY', Round(Selection.Position.Y));
end
else
begin
PosX := AnimIni.ReadInteger(IntToStr(Round(TimerBar.Value)) +
'_Object' + IntToStr(i), 'PosX', PosX);
PosY := AnimIni.ReadInteger(IntToStr(Round(TimerBar.Value)) +
'_Object' + IntToStr(i), 'PosY', PosY);
Selection.Position.X := PosX;
Selection.Position.Y := PosY;
end;
end;
end;
虽然我严重怀疑AnimIni.ReadInteger
函数的默认值,PosX
和PosY
是未分配的。如果找不到ini文件中的部分,则PosX
和PosY
将具有任意值。你应该将它们初始化为任何有意义的东西。
答案 1 :(得分:3)
您的循环计数器和索引属性不匹配。 ComponentCount
和Components[]
齐聚一堂。并ChildrenCount
和Children[]
在一起。您希望使用后一对,因为您对控件的子项感兴趣。 ComponentCount
和Components[]
属性是指所有权,这是一个不同的概念。
你的循环结束了什么,但你继续在循环变量之后使用循环变量。这显然是错的。看起来它需要在循环内部并在Scene.Children[i] is TSelection
测试中。
旁边ChildrenCount
在语法上与ComponentCount
和ControlCount
不一致。此属性应该已命名为ChildCount
。