VCL 原生 InputBox/InputQuery 存在明顯缺陷:按鈕標題固定為英文「OK/Cancel」、字體可能顯示異常(非中文系統)、無法顯示圖標、無密碼輸入模式。修改 VCL 源碼維護成本高,利用自定義消息 + 窗體鉤子可在不侵入 VCL 前提下優雅解決。
MY_INPUT_BOX = WM_USER + 101。InputBox 前,PostMessage 發送該消息給主窗體,攜帶參數(WParam:密碼模式;LParam:圖標模式)。WndProc 捕獲消息,在輸入對話框顯示前(模態循環啟動前)修改其屬性:字體、按鈕標題、添加圖標、設置密碼字符。class TfrmMain : public TForm {
__published: // ... 控件聲明
private:
void __fastcall WndProc(TMessage &Msg); // 重載消息處理
public:
// ...
};
#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); // 傳遞給默認處理
}
// 原生風格(圖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 | 可能異常 | 無 | 無 |
| 改良 | 確定/取消 | 跟隨主窗體 | 無 | 無 |
| 帶圖標 | 確定/取消 | 跟隨主窗體 | 左下角應用圖標 | 無 |
| 密碼框 | 確定/取消 | 跟隨主窗體 | 無 | 顯示 * |
CustomInputBox(const String& Caption, const String& Prompt, String& Value, bool Password=false, bool WithIcon=false) 靜態方法,業務代碼零感知調用。此方案以「最小侵入、最大靈活」解決 InputBox 長期痛點,是 C++Builder 開發者工具箱必備技巧。