Delphi 将子组件属性类型转换为ini文件

Delphi 将子组件属性类型转换为ini文件,delphi,delphi-xe2,firemonkey,Delphi,Delphi Xe2,Firemonkey,我现在很头疼组件属性的类型转换 在我的表格上,我有一个叫做“场景”的TPanel。同样在表单上,我有一个按钮创建一个t选择,在该t选择中创建一个t图像,然后将图片加载到该图像中。TSelection的名称通过称为“ImgObjName”的TEdit分配。然后,它将该名称写入一个文件。t选择的事件分配给代码中的其他程序。正如您所知,TSelection组件可以在运行时四处移动(并调整大小)。TImage的HitTest已关闭,而TSelection已打开 上面的工作,因为我希望它,但下一部分是我卡

我现在很头疼组件属性的类型转换

在我的表格上,我有一个叫做“场景”的TPanel。同样在表单上,我有一个按钮创建一个
t选择
,在该
t选择
中创建一个
t图像
,然后将图片加载到该图像中。TSelection的名称通过称为“ImgObjName”的TEdit分配。然后,它将该名称写入一个文件。t选择的事件分配给代码中的其他程序。正如您所知,TSelection组件可以在运行时四处移动(并调整大小)。TImage的HitTest已关闭,而TSelection已打开

上面的工作,因为我希望它,但下一部分是我卡住了。基本上,在计时器上,我想将每个子组件的一些选定属性写入TMemIniFile。有两种方法我愿意这样做
1) 写入每个子项的属性以分离tMeminifile。
2) 将每个子级的属性写入一个TMemIniFile,但使
部分
标识该部分中的值与哪个组件相关

我尝试了几种不同的方法,但它们都给我带来了一些重大问题(通常是“索引超出范围”)

我目前的方法就是这样

ChgPos
是一个全局布尔变量,当其中一个TSelection对象上的mousedown事件被激发时为TRUE,当MouseUp事件被激发时为FALSE。这个布尔过程非常适合这些目的,因此不需要进行任何更改

TimerBar
是在设计时创建的
TTrackBar
。它的值根据计时器而变化

AnimIni
是在代码前面分配的TMemIniFile。为此,我将其设置为不释放文件(以便不存在访问冲突)

我正在努力想办法解决这个问题。我得到了“索引超出范围”的错误。我还需要保存TImage组件属性(特别是父组件和位图位置,但我觉得让代码至少与一个组件一起工作对我来说很重要)

我对类型转换有点陌生(因为我以前的所有项目都是在不需要它的情况下工作的),但到目前为止,我在这方面的所有经验都非常成功。只是在这个特殊的案例中,它被证明变得比我在没有帮助的情况下所能解决的更复杂

我确实尝试过
WriteComponent
ReadComponent
并使用多个文件来实时传输与TimerBar值相关的数据,但对于我想要实现的目标来说,速度太慢了(特别是在写函数上)。inifile方法确实可以在我之前的测试中使用,但它实际上是在运行时创建的多个组件的类型转换中使用的,我对此有问题


有人能告诉我一个可能的解决方案或者我应该朝哪个方向走吗?

你的循环计数器和索引属性不匹配<代码>组件计数和
组件[]
一起进行。和
ChildrenCount
ChildrenCount[]
一起。您希望使用后一对,因为您对控件的子级很感兴趣。
ComponentCount
Components[]
属性是指所有权,这是一个不同的概念

更重要的是,循环结束,但在循环变量之后继续使用循环变量。这显然是错误的。它看起来需要在循环内部和
场景内部。Children[i]是t选择
测试


作为旁白,
ChildrenCount
ComponentCount
ControlCount
一起在语法上不正确。此属性应命名为
ChildCount

循环计数器和索引属性不匹配<代码>组件计数和
组件[]
一起进行。和
ChildrenCount
ChildrenCount[]
一起。您希望使用后一对,因为您对控件的子级很感兴趣。
ComponentCount
Components[]
属性是指所有权,这是一个不同的概念

更重要的是,循环结束,但在循环变量之后继续使用循环变量。这显然是错误的。它看起来需要在循环内部和
场景内部。Children[i]是t选择
测试

作为旁白,
ChildrenCount
ComponentCount
ControlCount
一起在语法上不正确。此属性应命名为
ChildCount

  • 您正在混合组件和子组件。如果循环遍历面板的所有子级,请不要在
    组件
    属性上使用该索引,而是在
    子级
    属性上使用该索引。(我假设您的代码已编译且XE2具有
    Children
    属性,否则我认为您的意思是
    控件
    控件计数
  • 与已经注释的lurd一样,您正在for循环外部使用for循环变量
    i
    。我肯定你想把它放在里面。编译器还警告您:

    FOR循环变量“i”在循环后可能未定义

    始终确保你有零!编译器错误、警告和提示

  • 我不理解你的常规逻辑,因为即使你真的想写,它也会加载设置。我认为只有当
    ChgPos
    为false时,才需要从MemIniFile加载设置
  • 没有给出任何保证,但我认为例程应该是这样的(包括一些语法改进):

    尽管我严重怀疑
    AnimIni.ReadInteger
    函数、
    PosX
    PosY
    的默认值,但它们都是未赋值的。如果ini文件中没有节
    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;
    
    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;