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

Delphi 12 MDI子窗体标题颜色修改方法咨询

Delphi 12 MDI子窗体标题/边框颜色修改方案

Delphi 12对MDI子窗体的样式升级确实解决了旧版本的风格适配问题,但直接对子窗体调用DwmSetWindowAttribute无效的原因是:MDI子窗体的标题栏并非由自身绘制,而是由MDI客户区(MDIClient窗口)负责渲染,所以需要针对MDIClient窗口做自定义处理。

以下是两种可行的解决方案:

方法一:子类化MDIClient窗口自定义绘制

通过子类化主窗体的MDIClient窗口,拦截WM_DRAWITEM消息来手动绘制子窗体的标题栏和边框,这是应用程序级别的自定义方案,不会影响系统其他程序。

示例代码

在主窗体中实现子类化逻辑:

type
  TMainForm = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    FMDIClientOldWndProc: Pointer;
    function MDIClientSubclassProc(Handle: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall;
  public
  end;

implementation

{$R *.dfm}

uses
  Winapi.Messages, Winapi.Windows, Vcl.Forms;

procedure TMainForm.FormCreate(Sender: TObject);
begin
  // 子类化MDIClient窗口
  FMDIClientOldWndProc := Pointer(GetWindowLongPtr(ClientHandle, GWLP_WNDPROC));
  SetWindowLongPtr(ClientHandle, GWLP_WNDPROC, LONG_PTR(@MDIClientSubclassProc));
end;

procedure TMainForm.FormDestroy(Sender: TObject);
begin
  // 恢复原窗口过程,避免程序崩溃
  if Assigned(FMDIClientOldWndProc) then
    SetWindowLongPtr(ClientHandle, GWLP_WNDPROC, LONG_PTR(FMDIClientOldWndProc));
end;

function TMainForm.MDIClientSubclassProc(Handle: HWND; Msg: UINT; wParam: WPARAM; lParam: LPARAM): LRESULT;
var
  MDIDrawInfo: PMDIDrawItemStruct;
  TitleBrush: HBRUSH;
  BorderBrush: HBRUSH;
  TextColor: COLORREF;
begin
  Result := CallWindowProc(FMDIClientOldWndProc, Handle, Msg, wParam, lParam);

  if Msg = WM_DRAWITEM then
  begin
    MDIDrawInfo := PMDIDrawItemStruct(lParam);
    if MDIDrawInfo^.CtlType = ODT_MDICHILD then
    begin
      // 根据子窗体活动状态设置颜色
      if MDIDrawInfo^.itemState and ODS_SELECTED <> 0 then
      begin
        TitleBrush := CreateSolidBrush(RGB(32, 32, 32)); // 活动窗口标题背景(深灰)
        BorderBrush := CreateSolidBrush(RGB(0, 120, 215)); // 活动窗口边框(蓝)
        TextColor := RGB(255, 255, 255); // 活动窗口标题文本(白)
      end
      else
      begin
        TitleBrush := CreateSolidBrush(RGB(240, 240, 240)); // 非活动窗口标题背景(浅灰)
        BorderBrush := CreateSolidBrush(RGB(180, 180, 180)); // 非活动窗口边框(灰)
        TextColor := RGB(64, 64, 64); // 非活动窗口标题文本(深灰)
      end;

      // 绘制标题栏背景
      FillRect(MDIDrawInfo^.hDC, MDIDrawInfo^.rcItem, TitleBrush);
      // 绘制边框
      FrameRect(MDIDrawInfo^.hDC, MDIDrawInfo^.rcItem, BorderBrush);
      // 绘制标题文本
      SetTextColor(MDIDrawInfo^.hDC, TextColor);
      SetBkMode(MDIDrawInfo^.hDC, TRANSPARENT);
      DrawText(MDIDrawInfo^.hDC, PChar(MDIDrawInfo^.itemData^.szTitle), -1, MDIDrawInfo^.rcItem, DT_LEFT or DT_VCENTER or DT_SINGLELINE);

      // 释放GDI资源
      DeleteObject(TitleBrush);
      DeleteObject(BorderBrush);

      Result := 1; // 标记消息已处理,阻止系统默认绘制
    end;
  end;
end;

方法二:修改系统主题(不推荐)

通过修改Windows注册表中MDI窗口的主题颜色配置,可以全局改变MDI子窗体的标题样式,但该方案会影响所有使用系统MDI样式的程序,不适合仅需自定义当前应用的场景。

注意事项

  • 子类化MDIClient窗口时,必须在主窗体销毁时恢复原窗口过程,否则会导致程序异常崩溃。
  • WM_DRAWITEM消息中的MDIDrawItemStruct包含子窗体的活动状态、标题文本、绘制区域等信息,可以根据需求灵活调整颜色和布局。

内容的提问来源于stack exchange,提问作者Daniel Marschall

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.04 16:33:18