Using the example provided here How to implement a close button for a TTabsheet of a TPageControl combined with setting a forms parent to a tab sheet with matching caption I was able to take my pagecontrol with forms attached as TTabSheet and add a close button and image from an image list much like you see on today's web browsers.
When I change
procedure TMainfrm.SOTest(Sender: TObject);
var
ATab: TTabSheet;
AForm: TMyForm;
begin
{ Tabbed }
ATab:= TTabSheet.Create(MainPageControl);
ATab.PageControl := MainPageControl;
MainPageControl.ActivePage := ATab;
AForm:= TMyForm.Create(ATab);
AForm.Show;
ATab.Caption := AForm.Caption;
end;
to
procedure TMainfrm.SOTest(Sender: TObject);
var
AForm: TMyForm;
begin
AForm:= TMyForm.Create(Application);
AForm.Show;
AForm.DragKind := dkDock;
AForm.DragMode := dmAutomatic;
AForm.ManualDock(MainPageControl,MainPageControl,alClient);
AForm.Caption := 'StackOverFlow';
end;
The OnMouse events do not pick up on any docked forms thus causing the close button to stop working.
Problem is, you're setting the DockSite
property of the page control (though it is not mentioned in the question). When DockSite is set, a drag object is created when left button of the mouse is pressed and then the mouse is captured by this object (this is done to be able to automatically drag out the form). Thus it is this object that processes the mouse messages until the capture is released, which is done in a WM_LBUTTONUP
case in TDragObject.WndProc
.
Overriding WndProc, deriving a new class and putting a message handler etc. will not work, because the page control is not delivered any mouse messages while the mouse is captured by the drag object. Even using Application.OnMessage would be clumsy at best since Msg.hwnd would point to a different window each time the mouse is clicked.
What you can do, for instance, is in one way or another subclass the page control to be able to intercept WM_LBUTTONDOWN
, perform a test there and release the capture if the click is on a tab buton. A very dirty quick example based on the linked question:
type
TPageControl = class(comctrls.TPageControl)
private
procedure WmLButtonDown(var Msg: TWMLButtonDown); message WM_LBUTTONDOWN;
end;
TMainfrm = class(TForm)
..
procedure TPageControl.WmLButtonDown(var Msg: TWMLButtonDown);
var
I: Integer;
begin
inherited; // mouse will be captured here
for I := 0 to Length(Mainfrm.FCloseButtonsRect) - 1 do
begin
if PtInRect(Mainfrm.FCloseButtonsRect[I], SmallPointToPoint(Msg.Pos)) then
begin
ReleaseCapture; // and released here
Break;
end;
end;
end;