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
相关产品推荐
相关产品推荐

