组件在Delphi 2K9中在运行时禁用和启用。奇怪的问题

时间:2009-07-25 05:22:28

标签: windows delphi controls components vcl

这是代码:

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不,没有冒犯,交配,没关系。我很高兴收到如此自愿和乐于助人的帖子。再次感谢。

3 个答案:

答案 0 :(得分: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参数的所有代码都可以简化为单个语句。这是因为启用已启用的控件,并禁用已禁用的控件,这是无操作。

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

答案 1 :(得分: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;

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

答案 2 :(得分:0)

这看起来确实应该有效。这是调试器可以提供的功能,而不仅仅是我们可以提供帮助。

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

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

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