首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C++ >> 關於C++

C++ Builder 自繪標題列實作範例:WM_NCHITTEST 與 WndProc 重載

     編輯:關於C++

透過攔截非客戶區訊息 (WM_NCPAINT、WM_NCHITTEST、WM_NCCALCSIZE) 並重載 WndProc,可完全自訂視窗標題列外觀與行為。本文提供一個將標題列繪製為垂直藍色條並顯示旋轉文字的完整範例。

核心技術點

  • CreateParams:移除標準標題列 (WS_DLGFRAME),改用 WS_POPUP。
  • WM_NCHITTEST:讓自繪區域響應 HTCAPTION,支援拖曳移動視窗。
  • FormPaint:在客戶區繪製自訂標題列圖形與文字。
  • WndProc:攔截 WM_SYSCOMMAND 處理最大化重繪。

完整程式碼

Unit1.h

#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

Unit1.cpp

#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();
}

關鍵細節解析

  1. WS_POPUP + 移除 WS_DLGFRAME:獲得無標準邊框視窗,客戶區涵蓋整個視窗,標題列需自行繪製於客戶區內。
  2. WM_NCHITTEST 返回 HTCAPTION:讓系統認為滑鼠在標題列上,自動處理拖曳移動、雙擊最大化等行為,無需手寫移動邏輯。
  3. 垂直文字繪製:lfEscapement=900 實現 90 度逆時針旋轉;TextOut 座標需配合旋轉後基線調整。
  4. WM_SYSCOMMAND 攔截最大化:最大化時客戶區尺寸變化,必須 Invalidate() 觸發重繪,否則自繪標題列會殘留舊尺寸內容。

擴展應用方向

  • 繪製漸變背景、圖片背景、圓角矩形標題列。
  • 整合最小化/最大化/關閉按鈕 (自繪或置入 TSpeedButton),於 WM_NCHITTEST 返回 HTMINBUTTON/HTMAXBUTTON/HTCLOSE。
  • 支援 WM_NCCALCSIZE 精確控制客戶區與非客戶區邊界。
  • 封裝為 TCustomForm 衍生類別,提供 TitleBarHeight、TitleBarColor、TitleBarFont 等設計時屬性。

此範例展示了 VCL 視窗非客戶區自繪的核心機制,為打造獨特視覺風格的應用程式奠定基礎。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved