【问题标题】:Typecast child component properties to ini file将子组件属性类型转换为 ini 文件
【发布时间】:2012-04-14 17:36:49
【问题描述】:

我目前非常头疼组件属性的类型转换。

在我的表单上,我有一个名为“场景”的 TPanel。同样在表单上,​​我有一个创建TSelection 的按钮,在该TSelection 中创建一个TImage,然后将图片加载到该TImage 中。 TSelection 的名称是通过称为“ImgObjName”的 TEdit 分配的。然后它将这个名字写入一个inifile。 TSelection 的事件被分配给代码中其他地方的过程。如您所知,TSelection 组件可以在运行时移动(和调整大小)。 TImage 的 HitTest 关闭,而 TSelection 开启。

上面的工作如我所愿,但下一部分是我卡住的地方。本质上,在计时器上,我想将每个子组件的一些属性选择写入 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 组件属性(尤其是父级和位图位置,但我觉得目前让代码与至少一个组件一起工作对我来说很重要)。

我对类型转换有点陌生(因为我以前的所有项目都不需要它),但到目前为止我的所有经验都非常成功。只是在这种特殊情况下,事实证明它变得比我在没有帮助的情况下可以解决的复杂得多。

我确实尝试过WriteComponentReadComponent,并使用多个文件实时流式传输与 TimerBar 的值相关的数据,但对于我想要实现的目标来说太慢了(尤其是在写入功能上)。 inifile 方法在我之前的测试中确实有效,但它实际上正在处理在运行时创建的多个组件的类型转换,我遇到了问题。

任何人都可以阐明潜在的解决方案或我应该前进的方向吗?

【问题讨论】:

  • 你的 i 循环结束得太快了。 if ChgPos(以及其他)中 i 的状态未确定。

标签: delphi delphi-xe2 firemonkey


【解决方案1】:
  1. 您正在混合组件和子项。如果您遍历面板的所有子项,请不要在 Components 属性上使用该索引,而是在 Children 属性上使用该索引。 (我假设您的代码已编译并且 XE2 具有 Children 属性,否则我认为您的意思是 ControlsControlCount)。
  2. 就像 LU RD 已经评论过的那样,您在 for 循环之外使用了 for 循环变量 i。我确定你想要它在里面。编译器还会警告您:

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

    始终确保您的值为零!编译器错误、警告和提示。

  3. 我不明白你的例行逻辑,因为它会加载设置,即使你真的想写它们。我认为您只想在 ChgPos 为 false 时从 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 函数的默认值PosXPosY,它们是未分配的。如果在 ini 文件中没有找到任何部分,则 PosXPosY 将具有任意值。您应该将它们初始化为任何有意义的值。

【讨论】:

  • 我猜 Children 属性必须是 FMX。
  • NGLN 就是这样。 “儿童”确实是 FMX 属性。事实上,没有关于循环的警告或提示(只有关于我没有在其他程序中使用过的变量)由于写得很好的解释和代码更正,我必须对你的回复投赞成票,但是由于有几个人提供了帮助,我对他们的每个答案都投了赞成票。
【解决方案2】:

您的循环计数器和索引属性不匹配。 ComponentCountComponents[] 一起去。和ChildrenCountChildren[] 一起去。您希望使用后一对,因为您对控件的子项感兴趣。 ComponentCountComponents[] 属性是指所有权,这是一个不同的概念。

更重要的是,您的循环结束了,但您在循环变量之后继续使用循环变量。这显然是错误的。看起来它需要在循环内和 Scene.Children[i] is TSelection 测试内。

顺便说一句,ChildrenCountComponentCountControlCount 在语法上不正确。这个属性应该被命名为ChildCount

【讨论】:

    猜你喜欢
    • 2013-06-23
    • 2016-06-05
    • 2019-12-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-07-17
    • 2020-01-23
    相关资源
    最近更新 更多