TPageControl bug in D4 - still in D6?
Everytime I have to deal with TPageControl in Delphi 4 it seems I find a bug.
This one is easy to reproduce.
Create a new application.
Put a TPageControl on Form1 and set DockSite = True for the TPageControl.
Add two pages (TTabsheets). Create a second form (Form2), set Visible = True,
DragKind = dkDock and DragMode = dmAutomatic.
Create a button on Form1 with the following code:
procedure TForm1.Button1Click(Sender: TObject);
begin
TabSheet1.TabVisible := False;
end;
Where Tabsheet1 is the first page on the TPageControl.
Run the project.
Dock Form2 on the TPageControl;
Click the button.
Now you cannot undock Form2 anymore.
I have traced the bug down to this function in the ComCtrls unit:
function TPageControl.GetDockClientFromMousePos(MousePos: TPoint): TControl;
var
HitIndex: Integer;
HitTestInfo: TTCHitTestInfo;
Page: TTabSheet;
begin
Result := nil;
if DockSite then
begin
HitTestInfo.pt := MousePos;
HitIndex := SendMessage(Handle, TCM_HITTEST, 0, Longint(@HitTestInfo));
if HitIndex >= 0 then
begin
Page := Pages[HitIndex];
if not Page.TabVisible then Page := FindNextPage(Page, True, True);
if (Page <> nil) and (Page.ControlCount > 0) then
begin
Result := Page.Controls[0];
if Result.HostDockSite <> Self then Result := nil;
end;
end;
end;
end;
This function obviously maps the HitIndex to the wrong TTabsheet,
if one of the pages with an index < HitIndex is not visible (TabVisible = False),
since the TCM_HITTEST message returns an index into the visible pages.
Has this bug been fixed in D6?
It can be fixed by the following code:
function TPageControl.GetDockClientFromMousePos(MousePos: TPoint): TControl;
var
HitIndex, PageIndex, VisibleIndex: Integer;
HitTestInfo: TTCHitTestInfo;
Page: TTabSheet;
begin
Result := nil;
if DockSite then
begin
HitTestInfo.pt := MousePos;
HitIndex := SendMessage(Handle, TCM_HITTEST, 0, Longint(@HitTestInfo));
if HitIndex >= 0 then
begin
VisibleIndex := -1;
for PageIndex := 0 to PageCount - 1 do
begin
Page := Pages[PageIndex];
if Page.TabVisible then Inc(VisibleIndex);
if VisibleIndex = HitIndex then
begin
if Page.ControlCount > 0 then
begin
Result := Page.Controls[0];
if Result.HostDockSite <> Self then Result := nil;
end;
Break;
end;
end;
end;
end;
end;
Karl