You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delphi 12.1无标题MDI子窗体WMHitTest失效问题求助

Delphi 12.1 MDI子窗体WM_NCHITTEST消息失效问题

问题描述

MDI子窗体通过重写CreateParams移除标题栏:

procedure CreateParams(var Params : TCreateParams) ; override ;
 
procedure TFormChart.CreateParams(var Params : TCreateParams) ;
begin
  inherited CreateParams(Params) ;
  Params.Style := (Params.Style) and (not ws_Caption) ;
end ;

同时通过重写WM_NCHITTEST消息,让窗体上的标签模拟标题栏功能(点击拖动、双击最大化):

procedure WMHitTest(VAR Msg: TWMNcHitTest); Message WM_NCHITTEST;

procedure TFormChart.WMHitTest(var Msg: TWMNcHitTest);
begin
  Inherited;

  //ScripNameRect contains the coords of the label which acts as the form caption
  if PtInRect(ScripNameRect,ScreenToClient(Point(Msg.XPos,Msg.YPos))) then
  begin
    Msg.Result := HTCAPTION ;
  end;
end;

该逻辑从Delphi 5到Delphi 11.3均正常运行,但升级到Delphi 12.1后,CreateParams仍正常生效(窗体无标题),但WMHitTest方法不再被调用。已知Delphi 12.1对MDI机制做了底层变更。

原因分析

Delphi 12.1调整了VCL MDI子窗体的消息路由:当子窗体移除ws_Caption样式后,WM_NCHITTEST这类非客户区消息不再直接发送给子窗体,而是由MDI父窗体的消息循环拦截处理,导致子窗体的重写方法无法触发。

解决方案

方案1:通过鼠标消息模拟标题栏行为

放弃依赖WM_NCHITTEST,直接拦截鼠标按下和双击消息来实现拖动和最大化功能:

// 声明消息处理方法
procedure WMLButtonDown(var Msg: TWMLButtonDown); message WM_LBUTTONDOWN;
procedure WMLButtonDblClk(var Msg: TWMLButtonDblClk); message WM_LBUTTONDBLCLK;

// 实现拖动逻辑
procedure TFormChart.WMLButtonDown(var Msg: TWMLButtonDown);
begin
  inherited;
  if PtInRect(ScripNameRect, ScreenToClient(Point(Msg.XPos, Msg.YPos))) then
  begin
    ReleaseCapture;
    Perform(WM_SYSCOMMAND, SC_MOVE or HTCAPTION, 0);
  end;
end;

// 实现双击最大化/还原逻辑
procedure TFormChart.WMLButtonDblClk(var Msg: TWMLButtonDblClk);
begin
  inherited;
  if PtInRect(ScripNameRect, ScreenToClient(Point(Msg.XPos, Msg.YPos))) then
  begin
    WindowState := IfThen(WindowState = wsMaximized, wsNormal, wsMaximized);
  end;
end;

方案2:调整窗体样式保留消息触发

如果希望继续使用WM_NCHITTEST,可以修改CreateParams,保留ws_Caption但隐藏标题栏的可见元素:

procedure TFormChart.CreateParams(var Params: TCreateParams);
begin
  inherited;
  // 保留ws_Caption以保证消息触发,移除边框和对话框框架
  Params.Style := Params.Style and not (ws_Border or ws_DlgFrame);
  // 添加工具窗口扩展样式,隐藏标题栏文字和按钮
  Params.ExStyle := Params.ExStyle or WS_EX_TOOLWINDOW;
end;

这种方式能让WM_NCHITTEST继续触发,同时保持窗体无可见标题栏的效果,需要根据实际需求调整边框样式。

总结

方案1更稳定,不受MDI底层变更影响,适合大多数场景;方案2需根据窗体样式需求微调,兼容性略差。

内容的提问来源于stack exchange,提问作者Shekar Arumugam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.24 14:40:21