我想在一个窗体中间显示一个 TPanel,它是其他窗体的 MDI 父窗体。某种“飞溅”形式,但不完全是。该面板将包含用户将调用 misc 的链接/按钮/快捷方式。职能。
主要要求是当我单击 MDI 子窗体时,TPanel 应放置在 MDI 子窗体下方。然而,事实上,TPanel 将始终停留在 MDI 子窗体之上。
调用 Panel.SendToBack 将使面板消失。我能怎么做?
我想在一个窗体中间显示一个 TPanel,它是其他窗体的 MDI 父窗体。某种“飞溅”形式,但不完全是。该面板将包含用户将调用 misc 的链接/按钮/快捷方式。职能。
主要要求是当我单击 MDI 子窗体时,TPanel 应放置在 MDI 子窗体下方。然而,事实上,TPanel 将始终停留在 MDI 子窗体之上。
调用 Panel.SendToBack 将使面板消失。我能怎么做?
您将需要覆盖面板WindowProc
,以便面板始终位于 MDI 子项的后面,例如:
TMainForm = class(TForm)
...
private
FPanelWndProc: TWndMethod;
procedure PanelWndProc(var M: TMessage);
end;
procedure TMainForm.FormCreate(Sender: TObject);
begin
Windows.SetParent(Panel1.Handle, ClientHandle);
// Override Panel1 WindowProc
FPanelWndProc := Panel1.WindowProc;
Panel1.WindowProc := PanelWndProc;
end;
procedure TMainForm.FormDestroy(Sender: TObject);
begin
// Restore Panel1 WindowProc
Panel1.WindowProc := FPanelWndProc;
end;
procedure TMainForm.PanelWndProc(var M: TMessage);
var
P: ^WINDOWPOS;
begin
if M.Msg = WM_WINDOWPOSCHANGING then
begin
P := Pointer(M.LParam);
// Always place panel at bottom
P.hwndInsertAfter := HWND_BOTTOM;
end;
FPanelWndProc(M);
end;
注意:要快速测试代码,可以通过以下方式创建 MDI 应用程序File -> New -> MDI Application
编辑:上面的代码实际上回答了你最初的问题。如果您希望您的“面板以某种方式表现为 MDI 子项”(您的评论引用),那么只需 (...hmmmm...) 使用 MDI 子项表单。即创建一个新的形式.FormStyle = fsMDIChild
,然后使用类似的东西:
SetWindowLong(Child.Handle, GWL_STYLE,
GetWindowLong(Child.Handle, GWL_STYLE) and not (WS_BORDER or WS_DLGFRAME or WS_SIZEBOX));
删除它的边框(因为简单的设置.BorderStyle = bsNone
不起作用)。
将您需要的任何内容放在该表单上,一旦您单击它,它将移动到其他 MDI 表单之上。
MDI 系统通过拥有一个单一窗口来工作,该窗口是所有 MDI 子窗口的父窗口,称为客户端窗口。该客户端窗口又是 MDI 窗体的子窗口。MDI 的 VCL 实现为您创建子窗口。您可以通过 ClientHandle 访问其窗口句柄。
由于客户端窗口是主窗体的子窗体,并且是所有 MDI 窗体的父窗体,因此您唯一的解决方案是使此面板成为客户端窗口的一部分。
您可以控制客户端窗口的绘制。您可以通过将客户端窗口的窗口过程替换为您自己的窗口过程来做到这一点。您还需要处理按钮点击等。但这很混乱。
现在,也许您可以让您的面板成为客户端窗口的子项。但我很确定这会搞砸你的 MDI,你确实证实了这一点。