Delphi 12 MDI: Change caption color?

224 Views Asked by At

Prior to Delphi 12, MDI children were displayed in the Windows 7 Aero design, even with Windows 11.

New to Delphi 12 is that the MDI children have the typical Windows 10/11 design, which is amazing in my opinion!

MDI children

However, I dislike that the caption of every MDI child is white, since white is usually the color of inactive windows. I wonder, can I somehow change the color of the MDI children's border to anything but white?

I have tried the following code, which works on the main form, but does not work on MDI children:

procedure TFormXYZ.CreateWnd;
var
  col: COLORREF;
begin
  inherited;
  col := 0; // black
  DwmSetWindowAttribute(WindowHandle, DWMWA_CAPTION_COLOR, @col, SizeOf(COLORREF));
  DwmSetWindowAttribute(WindowHandle, DWMWA_BORDER_COLOR, @col, SizeOf(COLORREF));
end;    

Thank you for the help.

2

There are 2 best solutions below

6
Uwe Raabe On BEST ANSWER

Since Delphi 12 MDI child forms are no longer drawn by Windows but by the VCL itself, more precisely, the drawing is handled by TChildFormMessageHandler. In this class the border color is taken from a constant cBorderColor, which has the value clWhite.

Unfortunately this class is private and there is no official way to replace the implementation or somehow tweak it, except by using your own copy of Vcl.Forms.pas.

Either way I suggest to file a feature request at Quality Portal having different border colors for active and inactive MDI child forms.

0
Bozzy On

Based on Uwe Raabe's answer, I've modified TChildFormMessageHandler.PaintBorder in Vcl.Forms.pas this way (search for cBorderColor and replace the nearby code):

cBorderColor = clActiveCaption;
cBorderColorInactive = clInactiveCaption;
cFrameColor: array[Boolean] of TColor = (clInactiveBorder, clActiveBorder);
cCaptionTextColor: array[Boolean] of TColor = (clGrayText, clCaptionText);

cButtonFillColor: array[TSysButtonType, TButtonDrawState] of TColor =
  ((cBorderColor, $002311E8, $007A70F1, cBorderColorInactive),
   (cBorderColor, $00E5E5E5, $00CCCCCC, cBorderColorInactive),
   (cBorderColor, $00E5E5E5, $00CCCCCC, cBorderColorInactive));

cButtonIconColor: array[TSysButtonType, TButtonDrawState] of TColor =
  ((clBlack, clWhite, clWhite, clGrayText),
   (clBlack, clBlack, clBlack, clGrayText),
   (clBlack, clBlack, clBlack, clGrayText));

...and, continuing to search for cBorderColor you'll find two more instances, replace with this code:

if FActive then
  LBuffer.Canvas.Brush.Color := cBorderColor
else
  LBuffer.Canvas.Brush.Color := cBorderColorInactive;

This way the MDI Child forms' border will have the same color as before, in particular it'll change based on the form's state, which is the most important thing in terms of UX.

The rounded corner is still missing, but I like the sharp style.

For the less experienced, you don't have to modify the original Vcl.Forms.pas, instead you have to copy it from Delphi's install dir to some folder in your project and (if it's not in the root folder) add it explicitly to your project.