Search code examples
delphidelphi-xetpagecontrol

List index out of bounds in TPageControl


I am stuck with a TPageControl that exhibits some strange behaviour..

The control has 3 pages but when I do

for I:=0 to PageControl.PageCount-1 do begin
  PageControl.Pages[I].TabVisible := False;
  PageControl.Pages[I].Visible    := Ord(iColorScale.GenerationMode) = I;
end;

I get a 'List index out of bounds (3)' error when executing the first line of the first iteration of the loop equivalent to

PageControl.Pages[0].TabVisible := False;

Now, when I view the PageControl properties in the debugger, everything seems to be in order. The PageCount is expectedly 3, and I can see all the pages and their properties, including TabVisible of page 0, in the evaluator

I'm using Delphi XE on a windows 7 machine.. Does anyone have an idea what is going on? I'm at a loss.


Solution

  • tldr: set PageControl.HandleNeeded before setting TabVisible.

    There is a good explanation here (by Greg Chapman): TabVisible on TabSheet and index error
    For future SO reference (copy/paste):

    If the PageControl's handle was destroyed (which can happen if setting some property in the PageControl or any of its parent windows causes a call to RecreateWnd), the PageControl saves the visible tabs in a TStringList (FSaveTabs). Setting TabVisible results in a call to this routine:

    procedure TTabSheet.SetTabShowing(Value: Boolean);
    var
      Index: Integer;
    begin
      if FTabShowing <> Value then
        if Value then
        begin
          FTabShowing := True;
          FPageControl.InsertTab(Self);
        end else
        begin
          Index := TabIndex;
          FTabShowing := False;
          FPageControl.DeleteTab(Self, Index);
        end;
    end; 
    

    During the call to FPageControl.DeleteTab, the PageControl will recreate its handle if necessary. In doing so, it tries to reset the visible tabs using FSaveTabs. However, it can get confused because one of the tabs that it added to FSaveTabs is now invisible (TabSheet.FTabShowing = false). This causes the IndexError. So the fix is to make sure the handle is recreated before setting TabVisible.