DelphiFAQ Home Search:

Changing my form's border color (custom border)

 

commentsThis article has not been rated yet. After reading, feel free to leave comments and rate it.

Question:

I need to change the color for my form's border within my application without changing the systemwide setting.


Answer:

You could set BorderStyle to bsNone and draw it yourself. This involves also drawing the caption bar. It's cleaner to intercept the WM_NCPAINT windows message and do your own drawing there.

Below is a unit (originally by C. Wijffels) that does this. Method TBcForm.GetCaptionRect shows how to calculate the to be painted rectangle using GetSystemMetrics() (in that case for the caption bar; the calculation for custom borders will be slightly different).

unit sBcForm;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  DsgnIntF;

type
  TBcForm = class(TForm)
  private
    { private declarations }
    FCaption: TCaption;
    procedure CMFontChanged(var Msg: TMessage);
      message CM_FONTCHANGED;
    procedure WMWinIniChange(var Msg: TWMWinIniChange);
      message WM_WININICHANGE;
    procedure WMNCPaint(var Msg: TWMNCPaint);
      message WM_NCPAINT;
    procedure WMNCActivate(var Msg: TWMNCActivate);
      message WM_NCACTIVATE;
    procedure WMSetText(var Msg: TWMSetText);
      message WM_SETTEXT;
    procedure WMSysCommand(var Msg: TWMSysCommand);
      message WM_SYSCOMMAND;
    procedure WMGetMinMaxInfo(var Msg: TWMGetMinMaxInfo);
      message WM_GETMINMAXINFO;
    procedure DrawCaption(AActive: boolean);
    function GetCaptionRect : TRect;
    procedure SetCaption(const Value: TCaption);
  protected
    { protected declarations }
  public
    { public declarations }
    constructor Create(AOwner: TComponent);
      override;
  published
    { published declarations }
    property Caption : TCaption read FCaption write SetCaption;
  end;

procedure register;

implementation

procedure register;
begin { register }
  RegisterCustomModule(TBcForm, TCustomModule)
end; { register }


{ TBcForm }
constructor TBcForm.Create(AOwner: TComponent);
begin { TBcForm.Create }
  inherited;
  inherited Caption := ''
end; { TBcForm.Create }


function TBcForm.GetCaptionRect : TRect;
var
  iRect: TRect;
begin { TBcForm.GetCaptionRect }
  with iRect do
    if (csDesigning in ComponentState) then
    begin
      Top := GetSystemMetrics(SM_CYSIZEFRAME);
      Bottom := Top;
      Left := GetSystemMetrics(SM_CXBORDER) + GetSystemMetrics(SM_CXSIZEFRAME);
      Right := 2 * Left + GetSystemMetrics(SM_CXSIZEFRAME) +
               3 * GetSystemMetrics(SM_CXSIZE);
      Bottom := Bottom + GetSystemMetrics(SM_CYSIZE);
      Left := Left + GetSystemMetrics(SM_CXSIZE)
    end { (csDesigning in ComponentState) }
    else
    begin
      if (BorderStyle in [bsSizeable, bsSizeToolWin]) then
      begin
        Top := GetSystemMetrics(SM_CYSIZEFRAME);
        Bottom := Top;
        Left := GetSystemMetrics(SM_CXBORDER) + GetSystemMetrics(SM_CXSIZEFRAME);
        Right := 2 * Left + GetSystemMetrics(SM_CXSIZEFRAME)
      end { (BorderStyle in [bsSizeable, bsSizeToolWin]) }
      else
      begin
        Top := GetSystemMetrics(SM_CYFIXEDFRAME);
        Bottom := Top;
        Left := GetSystemMetrics(SM_CXBORDER) + GetSystemMetrics(SM_CXFIXEDFRAME);
        Right := 2 * Left + GetSystemMetrics(SM_CXFIXEDFRAME)
      end; { not ((BorderStyle in [bsSizeable, bsSizeToolWin])) }
      if (BorderStyle in [bsToolWindow, bsSizeToolWin]) then
      begin
        Bottom := Bottom + GetSystemMetrics(SM_CYSMSIZE)
      end { (BorderStyle in [bsToolWindow, bsSizeToolWin]) }
      else
      begin
        Bottom := Bottom + GetSystemMetrics(SM_CYSIZE);
        if (BorderStyle<>bsDialog)
           and
           (biSystemMenu in BorderIcons) then
          Left := Left + GetSystemMetrics(SM_CXSIZE)
      end; { not ((BorderStyle in [bsToolWindow, bsSizeToolWin])) }
      if (BorderStyle in [bsToolWindow, bsSizeToolWin, bsDialog]) then
      begin
        if (biSystemMenu in BorderIcons) then
        begin
          Right := Right + GetSystemMetrics(SM_CXSIZE);
          if (biHelp in BorderIcons) then
            Right := Right + GetSystemMetrics(SM_CXSIZE)
        end; { (biSystemMenu in BorderIcons) }
      end { (BorderStyle in [bsToolWindow, bsSizeToolWin, bsDialog]) }
      else
      if (biSystemMenu in BorderIcons) then
      begin
        Right := Right + GetSystemMetrics(SM_CXSIZE);
        if (biMinimize in BorderIcons)
            or
           (biMaximize in BorderIcons) then
          Right := Right + 2 * GetSystemMetrics(SM_CXSIZE)
        else
        if (biHelp in BorderIcons) then
          Right := Right + GetSystemMetrics(SM_CXSIZE)
      end; { (biSystemMenu in BorderIcons) }
    end; { not ((csDesigning in ComponentState)) }
    GetWindowRect(Handle, Result);
  Result.Right := Result.Right - Result.Left - iRect.Right;
  Result.Left := iRect.Left;
  Result.Top := iRect.Top;
  Result.Bottom := iRect.Bottom
end; { TBcForm.GetCaptionRect }


procedure TBcForm.DrawCaption(AActive: boolean);
var
  iNCM: TNonClientMetrics;
  iRect: TRect;
  iCanvas: TCanvas;
  iFlags: integer;
begin { TBcForm.DrawCaption }
  if (BorderStyle<>bsNone) then
  begin
    iRect := GetCaptionRect;
    iCanvas := TCanvas.Create;
    iCanvas.Handle := GetWindowDC(Handle);
    with iCanvas do
      try
        Font := Self.Font;
        iNCM.cbSize := SizeOf(iNCM);
        SystemParametersInfo(SPI_GETNONCLIENTMETRICS, SizeOf(iNCM), @iNCM,
                             0);
        if (BorderStyle in [bsToolWindow, bsSizeToolWin]) then
          Font.Height := ((iNCM.lfCaptionFont.lfHeight * 7) div
                         8)
        else
          Font.Height := iNCM.lfCaptionFont.lfHeight;
        if (iNCM.lfCaptionFont.lfWeight<700) then
          Font.Style := []
        else
          Font.Style := [fsBold];
        Brush.Style := bsClear;
        iFlags := DT_EXPANDTABS or DT_LEFT or DT_VCENTER or DT_SINGLELINE or
                  DT_END_ELLIPSIS;
        iFlags := DrawTextBiDiModeFlags(iFlags);
        if (AActive) then
        begin
          Font.Color := GetSysColor(COLOR_BACKGROUND);
          OffsetRect(iRect, +1, +1);
          DrawText(Handle, PChar(Caption), -1, iRect, iFlags);
          OffsetRect(iRect, -1, -1);
          Font.Color := GetSysColor(COLOR_CAPTIONTEXT)
        end { (AActive) }
        else
          Font.Color := GetSysColor(COLOR_INACTIVECAPTIONTEXT);
        DrawText(Handle, PChar(Caption), -1, iRect, iFlags)
      finally
        ReleaseDC(Self.Handle, Handle);
        iCanvas.Free
      end; { try }
  end; { (BorderStyle<>bsNone) }
end; { TBcForm.DrawCaption }


procedure TBcForm.WMNCActivate(var Msg: TWMNCActivate);
begin { TBcForm.WMNCActivate }
  inherited;
  DrawCaption(Msg.Active)
end; { TBcForm.WMNCActivate }


procedure TBcForm.WMNCPaint(var Msg: TWMNCPaint);
begin { TBcForm.WMNCPaint }
  inherited;
  DrawCaption(Active)
end; { TBcForm.WMNCPaint }


procedure TBcForm.WMSetText(var Msg: TWMSetText);
begin { TBcForm.WMSetText }
  inherited;
  DrawCaption(Active)
end; { TBcForm.WMSetText }


procedure TBcForm.WMSysCommand(var Msg: TWMSysCommand);
begin { TBcForm.WMSysCommand }
  inherited;
  DrawCaption(Active)
end; { TBcForm.WMSysCommand }


procedure TBcForm.WMGetMinMaxInfo(var Msg: TWMGetMinMaxInfo);
begin { TBcForm.WMGetMinMaxInfo }
  inherited
  //  Msg.MinMaxInfo.ptMinTrackSize := Point(630, 475);
end; { TBcForm.WMGetMinMaxInfo }


procedure TBcForm.SetCaption(const Value: TCaption);
begin { TBcForm.SetCaption }
  if (FCaption<>Value) then
  begin
    FCaption := Value;
    Perform(WM_NCPAINT, 0, 0)
  end; { (FCaption<>Value) }
end; { TBcForm.SetCaption }


procedure TBcForm.CMFontChanged(var Msg: TMessage);
begin { TBcForm.CMFontChanged }
  inherited;
  Perform(WM_NCPAINT, 0, 0)
end; { TBcForm.CMFontChanged }


procedure TBcForm.WMWinIniChange(var Msg: TWMWinIniChange);
begin { TBcForm.WMWinIniChange }
  inherited;
  Perform(WM_NCPAINT, 0, 0)
end; { TBcForm.WMWinIniChange }


end.
You don't like the formatting? Check out SourceCoder then!
Content-type: text/html

Comments:

2012-10-29, 02:30:39
anonymous from China  

 

 

NEW: Optional: Register   Login
Email address (not necessary):

Rate as
Hide my email when showing my comment.
Please notify me once a day about new comments on this topic.
Please provide a valid email address if you select this option, or post under a registered account.
 

Show city and country
Show country only
Hide my location
You can mark text as 'quoted' by putting [quote] .. [/quote] around it.
Please type in the code:

Please do not post inappropriate pictures. Inappropriate pictures include pictures of minors and nudity.
The owner of this web site reserves the right to delete such material.

photo Add a picture: