Delphi内嵌表单焦点异常:fsNormal无法获焦及适配需求技术问询
Delphi 内嵌表单实现与焦点问题解析
在Delphi中,您可以通过修改TForm.Parent属性来在一个表单内部创建另一个表单。创建内嵌表单主要有两种方式:
普通表单(fsNormal)
以下是创建内嵌表单的示例代码:
with TForm.Create(Self) do begin Parent := Self; Caption := 'Test 1'; Width := 350; Height := 200; Show; end;
但此类表单存在交互异常:仅点击标题栏或调用Form.SetFocus才能让表单及其内部控件获取焦点;不过该类表单会显示在宿主表单的TWinControl或TGraphicControl控件之上。
![内嵌表单示例]
MDI表单(fsMDIChild)
更规范的实现方式是使用MDI表单,示例代码如下:
Form.Style := fsMDIForm; with TForm.Create(Self) do begin Parent := Self; Caption := 'Test 1'; Width := 350; Height := 200; FormStyle := fsMDIChild; Show; end; with TForm.Create(Self) do begin Parent := Self; Caption := 'Test 2'; Width := 350; Height := 200; FormStyle := fsMDIChild; Show; end;
此类表单可正常交互,效果如下:
![正常工作的MDI表单示例]
存在的问题
MDI表单本可满足需求,但存在两个问题:
fsMDIForm自带的"ClientEdge"边框- 宿主表单内的控件会显示在MDI表单之上
第一个问题可通过重写ClientWndProc解决,代码如下:
procedure ShowMDIClientEdge(ClientHandle: THandle; ShowEdge: Boolean); var Style: NativeInt; begin if ClientHandle <> 0 then begin Style := GetWindowLong(ClientHandle, GWL_EXSTYLE); if ShowEdge then if Style and WS_EX_CLIENTEDGE = 0 then Style := Style or WS_EX_CLIENTEDGE else Exit else if Style and WS_EX_CLIENTEDGE <> 0 then Style := Style and not WS_EX_CLIENTEDGE else Exit; SetWindowLong(ClientHandle, GWL_EXSTYLE, Style); SetWindowPos(ClientHandle, 0, 0, 0, 0, 0, SWP_FRAMECHANGED or SWP_NOACTIVATE or SWP_NOMOVE or SWP_NOSIZE or SWP_NOZORDER); end; end; procedure TForm1.ClientWndProc(var Message: TMessage); begin if Message.Msg = $3F then begin ShowMDIClientEdge(ClientHandle, false); Exit; end; inherited; end;
但第二个问题(MDI表单显示在控件下方)似乎无法解决,这使得fsNormal方式更具吸引力——如果它能正常获取焦点的话。
我需要的内嵌表单需满足以下条件:
- 限制在宿主表单客户区内,无法移出或显示到客户区外
- 显示在宿主表单内所有控件之上
- 可正常获取焦点
请问为何fsNormal类型的内嵌表单无法正常获取焦点?
内容的提问来源于stack exchange,提问作者Codrut
相关产品推荐
相关产品推荐

