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

C++ Builder 自訂控件開發:垂直標題列對話框完整實作

     編輯:關於C++

專案目標

建立一個可重複使用的對話框控件 (TvCaptionDlg),其視窗標題列位於左側垂直方向,文字由下而上 90 度旋轉,綠色背景,保留拖曳移動視窗功能。

核心技術點

  1. WM_NCHITTEST 攔截:將左側區域判定為 HTCAPTION,系統即賦予標題列拖曳行為
  2. SDK 繪圖:VCL TFont 不支援文字旋轉,需使用 CreateFontIndirect 設定 lfEscapement = 900 (0.1 度單位)
  3. 視窗樣式調整:覆寫 CreateParams 移除 WS_DLGFRAME、加入 WS_POPUP 實現無框自繪
  4. 控件封裝流程:TComponent 衍生 → __published 屬性 → RegisterComponents 註冊至工具箱

第一步:建立基底視窗類別 (TVCForm)

標頭檔 (vcap.h)

class TVCForm : public TForm {
__published:
    TBitBtn *BitBtn1;
    void __fastcall FormPaint(TObject *Sender);
    void __fastcall BitBtn1Click(TObject *Sender);
protected:
    void __fastcall OnNcHitTest(TMessage &Msg);
    void __fastcall CreateParams(TCreateParams &Params);
    BEGIN_MESSAGE_MAP
    MESSAGE_HANDLER(WM_NCHITTEST, TMessage, OnNcHitTest)
    END_MESSAGE_MAP(TForm)
public:
    __fastcall TVCForm(TComponent* Owner);
};

實作檔 (vcap.cpp) 關鍵邏輯

void __fastcall TVCForm::FormPaint(TObject *Sender) {
    // 1. 繪製左側 20px 綠色標題列
    Canvas->Pen->Color = clGreen;
    Canvas->Brush->Color = clGreen;
    Canvas->Rectangle(0, 0, 20, ClientHeight);

    // 2. SDK 繪製 90 度旋轉文字
    LOGFONT lf = {0};
    lf.lfHeight = -13;
    lf.lfWeight = FW_NORMAL;
    lf.lfEscapement = 900;          // 90 度 (單位 0.1 度)
    lstrcpy(lf.lfFaceName, "新細明體");

    HFONT hFont = CreateFontIndirect(&lf);
    HFONT hOld = (HFONT)SelectObject(Canvas->Handle, hFont);
    SetTextColor(Canvas->Handle, RGB(255,255,255));
    RECT rc = {0, 0, 20, ClientHeight};
    TextOut(Canvas->Handle, 3, ClientHeight - 3, Caption.c_str(), Caption.Length());
    SelectObject(Canvas->Handle, hOld);
    DeleteObject(hFont);
}

void __fastcall TVCForm::OnNcHitTest(TMessage &Msg) {
    TPoint pt = ScreenToClient(SmallPointToPoint(*(TSmallPoint*)&Msg.LParam));
    RECT rc = {0, 0, 20, ClientHeight};
    if (PtInRect(&rc, pt))
        Msg.Result = HTCAPTION;     // 告訴系統此處為標題列
    else
        DefaultHandler(&Msg);
}

void __fastcall TVCForm::CreateParams(TCreateParams &Params) {
    TForm::CreateParams(Params);
    Params.Style |= WS_POPUP;
    Params.Style &= ~WS_DLGFRAME;   // 移除對話框框架
}

第二步:封裝為設計時控件 (TvCaptionDlg)

控件單元 (vcapdlg.h/cpp)

// vcapdlg.h
class PACKAGE TvCaptionDlg : public TComponent {
private:
    AnsiString FCaption;
protected:
public:
    virtual __fastcall TvCaptionDlg(TComponent* Owner);
    virtual void __fastcall Execute();
__published:
    __property AnsiString Caption = {read=FCaption, write=FCaption};
};

// vcapdlg.cpp
#include "vcapdlg.h"
#include "vcap.cpp"   // 直接包含實作,注意註解掉 vcap.cpp 中的 #pragma package(smart_init)

namespace Vcapdlg {
    void __fastcall PACKAGE Register() {
        TComponentClass classes[1] = {__classid(TvCaptionDlg)};
        RegisterComponents("MyComponents", classes, 0);
    }
}

__fastcall TvCaptionDlg::TvCaptionDlg(TComponent* Owner) : TComponent(Owner) {
    FCaption = "My Vertical Caption";
}

void __fastcall TvCaptionDlg::Execute() {
    TVCForm* dlg = new TVCForm(Application);
    dlg->Caption = Caption;
    dlg->ShowModal();
    delete dlg;
}

關鍵實作細節

項目說明
#pragma package(smart_init)vcap.cpp 中必須註解掉,否則安裝套件時會失敗
包含 vcap.cpp而非 .obj,避免需先編譯產生 .obj 的麻煩
設計時屬性Caption 為 AnsiString,無需自訂屬性編輯器
DFM 資源BitBtn1 的 Caption/Kind 等非預設屬性需在執行期設定,或將 TVCForm 完整定義放入控件單元

安裝與使用

  1. 元件 → 安裝元件 → 加入 vcapdlg.cpp → 重建套件
  2. 工具箱 "MyComponents" 頁面出現 TvCaptionDlg
  3. 拖放至表單,設定 Caption 屬性
  4. 程式碼中呼叫 TvCaptionDlg1->Execute() 顯示對話框

參考資源

BCB 線上說明 "Creating custom components" 為最佳入門教材,本文實作參考其 "Making a dialog box a component" 範例並修正兩處已知問題。

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