我想在表单中间显示一个TPanel,它是其他表单的MDI父级。某种“泼溅”的形式,但并不完全。该面板将包含用户将调用misc的链接/按钮/快捷方式。功能
主要要求是当我点击MDI孩子时,TPanel应该放在MDI子表单下面。但是,就目前而言,TPanel将始终保持在MDI子表格之上。
调用Panel.SendToBack将使面板消失。我该怎么办?
答案 0 :(得分:6)
您需要覆盖Panel的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;
注意:要快速测试代码,您可以通过File -> New -> MDI Application
编辑:上面的代码实际上回答了您的初始问题。如果您希望“ Panel以某种方式表现为MDI孩子”(您的评论引用),那么只需(......嗯......)使用MDI Child表单。即使用.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表单之上。
答案 1 :(得分:1)
MDI系统的工作原理是拥有一个窗口,该窗口是所有MDI子窗口的父窗口,称为客户端窗口。反过来,该客户端窗口是MDI表单的子级。 MDI的VCL实现为您创建子窗口。您可以通过ClientHandle访问其窗口句柄。
由于客户端窗口是主窗体的子窗口,并且父窗口是所有MDI窗体,因此唯一的解决方案是使此面板成为客户端窗口的一部分。
您可以控制客户端窗口的绘制。您可以通过将客户端窗口的窗口proc替换为您自己的窗口proc来完成此操作。你还需要处理按钮点击等。但这非常混乱。
现在,也许你可以让你的面板成为客户端窗口的孩子。但我很确定这会搞砸你的MDI,事实证明你确实如此。