views:

27

answers:

1

On a form I put down 1 x TCategoryPanelGroup object and added 3 TCategoryPanel to it. In a routine, I need to go through each of TCategoryPanel and through each object onto those panel to produce an output.

So, here is the code ... why into the second FOR instead of giving me classname of each component (i.e. TButton, TLabel, etc) it gives out a TCategoryPanelSurface?

Short question: How can I access each controls from each TCategoryPanel?


procedure TForm1.Button2Click(Sender: TObject);
    var i,i2 : integer;

    begin
      for i := 0 to CategoryPanelGroup1.ControlCount-1 do
      begin
        showMessage((CategoryPanelGroup1.Controls[i] as TCategoryPanel).caption ) ;

        for i2 := 0 to (CategoryPanelGroup1.Controls[i] as TCategoryPanel).ControlCount-1 do
        begin

          showMessage((CategoryPanelGroup1.Controls[i] as TCategoryPanel).Controls[i2].ClassName);
        end;
      end;
    end;
A: 

You are looping through the Group's underlying TWinControl.Controls[] list when you should be looping through its TCategoryPanelGroup.Panels list instead.

As for why you are seeing a TCategoryPanelSurface appear, TCategoryPanel creates that object as a direct child of itself in its constructor. Any control you place into the Panel afterwards is actually a child of that TCategoryPanelSurface object, not a child of the TCategoryPanel itself. That is why your looping never sees those controls.

Unfortunately, TCategoryPanel does not expose direct access to its TCategoryPanelSurface object. So, in order to loop through its children, you have to first be able to access it. There are two possible ways to do that:

1)

procedure TForm1.Button2Click(Sender: TObject);
var
  i, j: integer;
  panel: TCategoryPanel;
  surface: TCategoryPanelSurface;
begin
  for i := 0 to CategoryPanelGroup1.Panels.Count-1 do
  begin
    panel := CategoryPanelGroup1.Panels[i] as TCategoryPanel;
    ShowMessage(panel.Caption);
    surface := panel.Controls[0] as TCategoryPanelSurface;
    for j := 0 to surface.ControlCount-1 do
    begin
      ShowMessage(surface.Controls[j].ClassName);
    end;
  end; 
end; 

2)

type
  TCategoryPanelAccess = class(TCategoryPanelAccess)
  end;

procedure TForm1.Button2Click(Sender: TObject);
var
  i, j: integer;
  panel: TCategoryPanel;
  surface: TCategoryPanelSurface;
begin
  for i := 0 to CategoryPanelGroup1.Panels.Count-1 do
  begin
    panel := CategoryPanelGroup1.Panels[i] as TCategoryPanel;
    ShowMessage(panel.Caption);
    surface := TCategoryPanelAccess(panel).FPanelSurface;
    for j := 0 to surface.ControlCount-1 do
    begin
      ShowMessage(surface.Controls[j].ClassName);
    end;
  end; 
end; 
Remy Lebeau - TeamB
I used your solution 1) but with a little fix into your code.line : panel := CategoryPanelGroup1.Panels[i] as TCategoryPanel;becomes : panel := CategoryPanelGroup1.Panels[i];Thanks again, work's fine !
Jaune Citron
The Panels property is a TList, which contains untyped Pointer values. That is why I was type-casting those pointers when accessing them.
Remy Lebeau - TeamB