HX_unbanned
HX_unbanned

Reputation: 597

Component disabling and enabling at runtime in Delphi 2K9. Weird problem

Here is code:

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;

I think no more explanations are needed. The ShowMessage correctly shows name of each component, but nothing is added in StringLists. Why?


UPDATE: As question has gone pretty wild, I did confirm answer, which a bit helped me.

I understand that I did write things pretty unclear, but I am very limited, because these code lines is part of commercial project, and my hobby and heart thing. The main problem was found already 6h ago, but Rob just wanted to extend this whole question :D No, no offense, mate, it's OK. I am happy to receive so willing and helpful posts. Thanks again.

Upvotes: 1

Views: 2002

Answers (3)

Argalatyr
Argalatyr

Reputation: 4659

Emphasizing that this is largely based on Rob's excellent suggestions, it looks as though you could simplify the code to:

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;

Not clear what the stringlists were for, since their contents were lost when execution left the scope of this procedure. If you want to return them, you should create and free them in the calling code.

Upvotes: 2

Rob Kennedy
Rob Kennedy

Reputation: 163357

How do you know that nothing is added to the lists? You create them in this code and the only references to them are in local variables. The objects are leaked when this function returns, so you never actually use the lists anywhere.

You've said you have code for "modular testing." Since that code isn't here, I must assume the code is not part of this function. But if you have external code that's supposed to check the contents of the lists, then the lists can't be just local variables. No other code can access them. You need to either return those lists or accept lists from outside that you then fill. Here's an example of the latter:

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;

The caller of this function will need to provide a TStrings descendant for each list. They could be TStringList, or they could be other descendants, such as TMemo.Lines, so you can directly observe their contents in your program. (They can't be just TStrings, though, since that's an abstract class.)


As you can see, I made some other changes to your code. All your code using the Reenable parameter can be simplified to a single statement. That's because enabling a control that's already enabled, and disabling a control that's already disabled, are no-ops.

Also, Name is a public property of TComponent. You don't need to type-cast to TControl before reading that property, but since you're type-casting so often elsewhere, it made sense to introduce a new variable to hold the type-casted TControl value, and that can make your code easier to read. Easier-to-read code is easier-to-understand code, and that makes it easier to debug.

Upvotes: 4

Mason Wheeler
Mason Wheeler

Reputation: 84650

That sure looks like it ought to work. This is the sort of thing that the debugger can probably help with more than we can here.

Try breaking the problematic line down into multiple lines, like so:

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

Rebuild with the "Use Debug DCUs" option on, and place a breakpoint on the if statement. Then use F7 to trace your way through the logic and see what's going on.

Upvotes: 0

Related Questions