8

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.

kobik
  • 21,001
  • 4
  • 61
  • 121
Bjarke Moholt
  • 313
  • 1
  • 4
  • 20
  • What happens if you try to run `PageControl.Pages[0].TabVisible := False;` outside of a loop? – Fenistil Jul 20 '15 at 12:39
  • 2
    Try setting `PageControl.HandleNeeded` before setting `TabVisible` to false. (http://www.delphigroups.info/2/d7/305018.html) – kobik Jul 20 '15 at 13:40
  • @Fenistil I get the same list index out of bounds error when running PageControl.Pages[0].TabVisible := False; outside the loop – Bjarke Moholt Jul 20 '15 at 13:43
  • 1
    @kobik PageControl.HandleNeeded solved the problem, thanks a bunch! – Bjarke Moholt Jul 20 '15 at 13:49
  • @kobik, can you expend that comment into an answer? – Johan Jul 21 '15 at 05:15
  • @Johan, done. I think it's a good question and deserves a reference on SO also (in case delphigroups link will die). personally I could not reproduce this error (D5/XP). – kobik Jul 21 '15 at 07:53

1 Answers1

8

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.

kobik
  • 21,001
  • 4
  • 61
  • 121