1

这是代码:

procedure DisableContrlOL(const cArray : array of string; ReEnable : boolean = False);
// can be called from VKP / RAW / Generation clicks
var
  AComponent: TComponent;
  CompListDis, CompListEna : TStringList;
begin
  CompListDis := TStringList.Create;
  CompListEna := TStringList.Create;
  for i := Low(cArray) to High(cArray) do begin
    AComponent := FindComponent(cArray[i]);
    if Assigned(AComponent) then
      if (AComponent is TControl) then begin
        if TControl(AComponent).Enabled then
          CompListEna.Add(TControl(AComponent).Name)
        else
          CompListDis.Add(TControl(AComponent).Name);
        ShowMessage(TControl(AComponent).Name);
        if ReEnable then begin // if reenabling needed, then all whi
          if not TControl(AComponent).Enabled then
            TControl(AComponent).Enabled := True;
        end else if (TControl(AComponent).Enabled) then
          TControl(AComponent).Enabled := False;
      end;
  end;
end;

我觉得不需要再解释了。ShowMessage 正确显示了每个组件的名称,但在 StringLists 中没有添加任何内容。为什么?


更新:由于问题变得非常疯狂,我确实确认了答案,这对我有所帮助。

我知道我确实写的东西很不清楚,但我很有限,因为这些代码行是商业项目的一部分,是我的爱好和内心的东西。主要问题已在 6 小时前发现,但 Rob 只是想扩展整个问题 :D 不,无意冒犯,伙计,没关系。我很高兴收到如此愿意和有帮助的帖子。再次感谢。

4

3 回答 3

4

你怎么知道列表中没有添加任何内容?您在此代码中创建它们,并且对它们的唯一引用是在局部变量中。当此函数返回时,对象会泄漏,因此您永远不会在任何地方实际使用列表。

你说过你有“模块化测试”的代码。由于该代码不在这里,我必须假设该代码不是该函数的一部分。但是,如果您有应该检查列表内容的外部代码,那么列表不能只是局部变量。没有其他代码可以访问它们。您需要返回这些列表或接受来自外部的列表然后填写。这是后者的一个例子:

procedure DisableContrlOL(const cArray: array of string;
                          Reenable: Boolean
                          CompListDis, CompListEna: TStrings);
// can be called from VKP / RAW / Generation clicks
var
  AComponent: TComponent;
  AControl: TControl;
  i: Integer;
begin
  for i := Low(cArray) to High(cArray) do begin
    AComponent := FindComponent(cArray[i]);
    if not Assigned(AComponent) or not (AComponent is TControl) then
      continue;

    AControl := TControl(AComponent);
    if AControl.Enabled then
      CompListEna.Add(AControl.Name)
    else
      CompListDis.Add(AControl.Name);
    ShowMessage(AControl.Name);

    AControl.Enabled := Reenable;
  end;
end;

此函数的调用者需要TStrings为每个列表提供一个后代。它们可以是TStringList,也可以是其他后代,例如TMemo.Lines,因此您可以在程序中直接观察它们的内容。(但是,它们不能只是TStrings,因为这是一个抽象类。)


如您所见,我对您的代码进行了一些其他更改。使用该参数的所有代码Reenable都可以简化为一条语句。这是因为启用已启用的控件和禁用已禁用的控件是无操作的。

此外,Name是 的公共财产TComponent。您不需要TControl在读取该属性之前进行类型转换,但由于您经常在其他地方进行类型转换,因此引入一个新变量来保存类型转换的TControl值是有意义的,这可以使您的代码更容易读书。更容易阅读的代码是更容易理解的代码,这使得调试更容易。

于 2009-07-25T06:32:41.927 回答
2

强调这主要基于 Rob 的出色建议,看起来您可以将代码简化为:

procedure DisableContrlOL(const cArray : array of string; 
                                ReEnable : boolean = False);
var
  AComponent: TComponent;
begin
  for i := Low(cArray) to High(cArray) do 
  begin
    AComponent := FindComponent(cArray[i]);
    if Assigned(AComponent) then
      if (AComponent is TControl) then 
      begin
        ShowMessage(TControl(AComponent).Name);
        TControl(AComponent).Enabled := ReEnable; 
      end;
  end;
end;

不清楚字符串列表的用途,因为当执行离开此过程的范围时,它们的内容会丢失。如果你想返回它们,你应该在调用代码中创建并释放它们。

于 2009-07-25T14:49:57.160 回答
0

看起来它应该可以工作。这是调试器可能比我们在这里所能提供的更多帮助的事情。

尝试将有问题的行分解为多行,如下所示:

  if TControl(AComponent).Enabled then
    CompListEna.Add(TControl(AComponent).Name)
  else CompListDis.Add(TControl(AComponent).Name);

使用“使用调试 DCU”选项进行重建,并在if语句上放置一个断点。然后使用 F7 跟踪您的逻辑并查看发生了什么。

于 2009-07-25T05:29:33.897 回答