針對現象:新手在構造函數中直接操作控件導致 ASSERT 失敗
// 錯誤代碼
CMyDialog dlg;
dlg.m_btnOK.SetWindowText(_T("新標題")); // Debug 斷言失敗:m_hWnd == NULL
錯誤指向 AFXWIN2.INL 第 40 行:ASSERT(::IsWindow(m_hWnd))。
CDialog 構造函數僅創建「容器」對象,不創建實際窗口及子控件。
DoModal() 內部調用 CreateIndirect → 創建窗口 → OnInitDialog → 運行消息泵 → EndDialog → 銷毀窗口。Create(IDD, pParent) 顯式創建窗口,之後可隨時操作控件。因此:控件的 m_hWnd 只有在 DoModal() 或 Create() 執行期間才有效。
// CMyDialog.h
class CMyDialog : public CDialog {
CString m_strBtnTitle;
public:
void SetButtonTitle(LPCTSTR sz) { m_strBtnTitle = sz; }
// ...
};
// CMyDialog.cpp
BOOL CMyDialog::OnInitDialog() {
CDialog::OnInitDialog();
if (!m_strBtnTitle.IsEmpty()) m_btnOK.SetWindowText(m_strBtnTitle);
return TRUE;
}
// 調用處
CMyDialog dlg;
dlg.SetButtonTitle(_T("確定並繼續"));
dlg.DoModal();
class CMyDialog : public CDialog {
public:
CString m_strBtnTitle; // public
// ...
};
// 調用處
CMyDialog dlg;
dlg.m_strBtnTitle = _T("直接賦值");
dlg.DoModal();
class CMyDialog : public CDialog {
CString m_strTitle;
public:
CMyDialog(LPCTSTR szTitle, CWnd* pParent = NULL)
: CDialog(IDD_MYDIALOG, pParent), m_strTitle(szTitle) {}
// ...
};
// 調用處
CMyDialog dlg(_T("帶參數構造"));
dlg.DoModal();
雖然全局變量能「解決問題」,但:
建議:僅在極簡原型驗證或極少數跨模塊狀態共享時使用,且需嚴格命名規範(如 g_ 前綴)。
CMyDialog* pDlg = new CMyDialog;
pDlg->Create(IDD_MYDIALOG, this); // 此後可直接操作控件
pDlg->m_btnOK.SetWindowText(_T("動態修改"));
pDlg->ShowWindow(SW_SHOW);
// 銷毀時需 delete pDlg(通常在 PostNcDestroy 中)
構造不創窗,DoModal/Create 纔是娘;
數據先存成員,OnInitDialog 再佈陣。
Setter 封裝最優雅,構造傳參也方便;
全局變量像毒藥,非不得已莫輕嘗。