透過攔截非客戶區訊息 (WM_NCPAINT、WM_NCHITTEST、WM_NCCALCSIZE) 並重載 WndProc,可完全自訂視窗標題列外觀與行為。本文提供一個將標題列繪製為垂直藍色條並顯示旋轉文字的完整範例。
WS_DLGFRAME),改用 WS_POPUP。HTCAPTION,支援拖曳移動視窗。WM_SYSCOMMAND 處理最大化重繪。#ifndef wmncH
#define wmncH
#include <Classes.hpp>
#include <Controls.hpp>
#include <StdCtrls.hpp>
#include <Forms.hpp>
#include <Buttons.hpp>
class TForm1 : public TForm {
__published:
TBitBtn *BitBtn1;
void __fastcall FormPaint(TObject *Sender);
void __fastcall FormResize(TObject *Sender);
void __fastcall BitBtn1Click(TObject *Sender);
private:
void __fastcall OnNcHitTest(TMessage &Message);
public:
__fastcall TForm1(TComponent* Owner);
BEGIN_MESSAGE_MAP
VCL_MESSAGE_HANDLER(WM_NCHITTEST, TMessage, OnNcHitTest)
END_MESSAGE_MAP(TForm)
protected:
virtual void __fastcall WndProc(TMessage &Message);
virtual void __fastcall CreateParams(TCreateParams &Params);
};
extern PACKAGE TForm1 *Form1;
#endif
#include <vcl.h>
#pragma hdrstop
#include "wmnc.h"
#pragma package(smart_init)
#pragma resource "*.dfm"
TForm1 *Form1;
__fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) {}
void __fastcall TForm1::CreateParams(TCreateParams &Params) {
TForm::CreateParams(Params);
Params.Style |= WS_POPUP;
Params.Style ^= WS_DLGFRAME; // 移除標準對話框框架
}
void __fastcall TForm1::OnNcHitTest(TMessage &Message) {
TPoint PT;
PT.x = LOWORD(Message.LParam);
PT.y = HIWORD(Message.LParam);
PT = ScreenToClient(PT);
RECT rect;
::SetRect(&rect, 0, 0, 20, ClientHeight); // 左側 20 像素區域
if (PtInRect(&rect, PT)) {
Message.Result = HTCAPTION; // 視為標題列,可拖曳
} else {
DefaultHandler(&Message);
}
}
void __fastcall TForm1::FormPaint(TObject *Sender) {
RECT rect;
::SetRect(&rect, 0, 0, ClientWidth, ClientHeight);
Canvas->Pen->Color = clBlue;
Canvas->Brush->Color = clBlue;
Canvas->Rectangle(0, 0, 20, ClientHeight); // 繪製左側藍色條
// 建立垂直字型
char *msg = "My Fellow Citizens!";
LOGFONT fontRect = {0};
fontRect.lfHeight = -13;
fontRect.lfWeight = FW_NORMAL;
fontRect.lfEscapement = 900; // 90 度 (單位 0.1 度)
lstrcpy(fontRect.lfFaceName, "新細明體");
HFONT hFont = CreateFontIndirect(&fontRect);
HFONT hOld = (HFONT)::SelectObject(Canvas->Handle, hFont);
::SetRect(&rect, 0, 0, 20, ClientHeight);
::SetTextColor(Canvas->Handle, RGB(255,255,255)); // 白字
::SetBkColor(Canvas->Handle, RGB(255,0,0)); // 紅底 (演示用)
::TextOut(Canvas->Handle, 3, ClientHeight-3, msg, lstrlen(msg));
::SelectObject(Canvas->Handle, hOld);
::DeleteObject(hFont);
}
void __fastcall TForm1::WndProc(TMessage &Message) {
if (Message.Msg == WM_SYSCOMMAND) {
if (Message.WParam == SC_MAXIMIZE || Message.WParam == 61490) { // 61490 為雙擊標題列最大化
Invalidate(); // 觸發重繪
}
}
TForm::WndProc(Message);
}
void __fastcall TForm1::FormResize(TObject *Sender) {
Invalidate(); // 大小改變重繪
}
void __fastcall TForm1::BitBtn1Click(TObject *Sender) {
int button = Application->MessageBox("Do you want to exit this form?",
"Confirmation", MB_YESNO | MB_ICONQUESTION);
if (button == IDYES) Application->Terminate();
}
lfEscapement=900 實現 90 度逆時針旋轉;TextOut 座標需配合旋轉後基線調整。Invalidate() 觸發重繪,否則自繪標題列會殘留舊尺寸內容。TSpeedButton),於 WM_NCHITTEST 返回 HTMINBUTTON/HTMAXBUTTON/HTCLOSE。WM_NCCALCSIZE 精確控制客戶區與非客戶區邊界。TCustomForm 衍生類別,提供 TitleBarHeight、TitleBarColor、TitleBarFont 等設計時屬性。此範例展示了 VCL 視窗非客戶區自繪的核心機制,為打造獨特視覺風格的應用程式奠定基礎。