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

C++Builder 自定義消息重構 InputBox:中文化、密碼框、圖標、字體統一

     編輯:VC 教學

痛點:原生 InputBox 的局限

VCL 原生 InputBox/InputQuery 存在明顯缺陷:按鈕標題固定為英文「OK/Cancel」、字體可能顯示異常(非中文系統)、無法顯示圖標、無密碼輸入模式。修改 VCL 源碼維護成本高,利用自定義消息 + 窗體鉤子可在不侵入 VCL 前提下優雅解決。

核心思路:消息驅動的運行時修改

  1. 定義自定義消息 MY_INPUT_BOX = WM_USER + 101。
  2. 調用 InputBox 前,PostMessage 發送該消息給主窗體,攜帶參數(WParam:密碼模式;LParam:圖標模式)。
  3. 主窗體重寫 WndProc 捕獲消息,在輸入對話框顯示前(模態循環啟動前)修改其屬性:字體、按鈕標題、添加圖標、設置密碼字符。

完整實現代碼

1. 頭文件聲明

class TfrmMain : public TForm {
__published: // ... 控件聲明
private:
    void __fastcall WndProc(TMessage &Msg); // 重載消息處理
public:
    // ...
};

2. 源文件實現

#define MY_INPUT_BOX WM_USER + 101

void __fastcall TfrmMain::WndProc(TMessage &Msg) {
    if (Msg.Msg == MY_INPUT_BOX) {
        // 參數解析
        // WParam: 0=普通, 1=密碼框
        // LParam: 0=普通, 1=帶圖標

        TForm *frm = Screen->Forms[0]; // 獲取最頂層模態對話框
        if (frm != this) { // 確保是輸入框而非主窗體
            // 1. 統一字體(建議主窗體設置為 宋體/微軟雅黑 9pt)
            frm->Font->Assign(Font);

            // 2. 修改按鈕標題為中文
            HWND hBtnOK = FindWindowEx(frm->Handle, NULL, "TButton", "OK");
            HWND hBtnCancel = FindWindowEx(frm->Handle, NULL, "TButton", "Cancel");
            if (hBtnOK) SetWindowText(hBtnOK, "確定(&O)");
            if (hBtnCancel) SetWindowText(hBtnCancel, "取消(&C)");

            // 3. 添加圖標 (LParam == 1)
            if (Msg.LParam == 1) {
                TImage *img = new TImage(frm); // Owner=frm,自動釋放
                img->Picture->Assign(Application->Icon); // 或加載自定義圖標
                img->Left = 11;
                img->Top = 60;
                img->Parent = frm;
                img->Show();
            }

            // 4. 密碼框模式 (WParam == 1)
            if (Msg.WParam == 1) {
                HWND hEdit = FindWindowEx(frm->Handle, NULL, "TEdit", NULL);
                if (hEdit)
                    SendMessage(hEdit, EM_SETPASSWORDCHAR, WPARAM('*'), 0);
            }
        }
    }
    TForm::WndProc(Msg); // 傳遞給默認處理
}

3. 調用示例:四種風格一鍵切換

// 原生風格(圖1:英文按鈕、字體問題)
void __fastcall TfrmMain::btnOldStyleClick(TObject *Sender) {
    String s = InputBox("原先的輸入對話框", "請輸入:", "");
    if (s.Trim().Length() > 0) ShowMessage(s);
}

// 改良風格(圖2:中文按鈕、字體正常)
void __fastcall TfrmMain::btnNewStyleClick(TObject *Sender) {
    PostMessage(Handle, MY_INPUT_BOX, 0, 0); // 關鍵行
    String s = InputBox("新的輸入對話框", "請輸入:", "");
    if (s.Trim().Length() > 0) ShowMessage(s);
}

// 帶圖標風格(圖3)
void __fastcall TfrmMain::btnWithImageClick(TObject *Sender) {
    PostMessage(Handle, MY_INPUT_BOX, 0, 1); // LParam=1
    String s = InputBox("帶圖片效果", "請輸入:", "默認文本");
    if (s.Trim().Length() > 0) ShowMessage(s);
}

// 密碼輸入風格(圖4)
void __fastcall TfrmMain::btnPwdStyleClick(TObject *Sender) {
    PostMessage(Handle, MY_INPUT_BOX, 1, 0); // WParam=1
    String s = InputBox("密碼輸入框", "請輸入密碼:", "");
    if (s.Trim().Length() > 0) ShowMessage(s);
}

效果對比

風格按鈕標題字體圖標密碼掩碼
原生OK/Cancel可能異常無無
改良確定/取消跟隨主窗體無無
帶圖標確定/取消跟隨主窗體左下角應用圖標無
密碼框確定/取消跟隨主窗體無顯示 *

技術亮點與避坑指南

  • PostMessage 而非 SendMessage:異步投遞,確保消息在模態循環啟動前被處理,修改生效。
  • Screen->Forms[0]:模態對話框彈出時位於 Forms 列表首位,可靈活獲取其 Handle。
  • FindWindowEx 精確定位子控件:按類名("TButton"、"TEdit")和標題查找,無需遍歷。
  • TImage Owner 設置為 frm:對話框關閉時自動釋放圖片資源,無內存洩漏。
  • 兼容性:僅依賴 VCL 運行時機制,無第三方依賴,支持 C++Builder 所有版本。

擴展建議

  • 封裝為 CustomInputBox(const String& Caption, const String& Prompt, String& Value, bool Password=false, bool WithIcon=false) 靜態方法,業務代碼零感知調用。
  • 支持更多定制:輸入長度限制、正則驗證、下拉選項(需替換為自定義 Form 實現)。

此方案以「最小侵入、最大靈活」解決 InputBox 長期痛點,是 C++Builder 開發者工具箱必備技巧。

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