在 Windows 程式設計中,對話框是使用者介面的核心元素之一。根據行為模式不同,對話框分為「模式」與「無模式」兩種類型。模式對話框會獨佔使用者輸入焦點,必須關閉後才能操作其他視窗;而無模式對話框則允許使用者同時與其他視窗互動,行為類似於獨立的彈出視窗。本文將深入探討 MFC 架構下無模式對話框的建立、顯示與物件銷毀機制,並提供兩種實用的記憶體管理策略。
建立無模式對話框需呼叫 CDialog::Create() 方法載入對話框資源,並以 ShowWindow(SW_SHOW) 使其顯示。若僅呼叫 Create() 而未顯示,對話框將保持不可見狀態。典型程式碼如下:
void CYourView::OnOpenDlg(void)
{
// 假設 IDD_TEST_DLG 為已定義的對話框資源 ID
CTestDlg *dlg = new CTestDlg;
dlg->Create(IDD_TEST_DLG, NULL);
dlg->ShowWindow(SW_SHOW);
// 此處不可呼叫 delete dlg;
}
關鍵在於:對話框物件以動態配置方式建立(new),且在函數結束時不得立即刪除。若物件被銷毀而視窗仍在顯示,將導致存取違規錯誤。因此,核心問題在於:何時、由誰負責銷毀該物件?
此法讓對話框在關閉時自行銷毀物件。重寫 OnOK()、OnCancel() 呼叫父類別方法後執行 DestroyWindow() 強制銷毀視窗;再對映 WM_DESTROY 訊息,在處理函數中執行 delete this 刪除自身。
void CTestDlg1::OnOK()
{
CDialog::OnOK();
DestroyWindow();
}
void CTestDlg1::OnCancel()
{
CDialog::OnCancel();
DestroyWindow();
}
void CTestDlg1::OnDestroy()
{
CDialog::OnDestroy();
AfxMessageBox(_T("call delete this"));
delete this;
}
此策略精髓在於:視窗銷毀時同步刪除物件。外部隨時呼叫 DestroyWindow() 即可觸發完整銷毀流程(DestroyWindow() 會引發 OnDestroy())。
適用於需由外部統一管理對話框生命週期的情境。步驟如下:
WM_DELETE_DLG 用於通知銷毀。m_pParent(不可為暫時性指標)。OnDestroy() 中以 PostMessage() 發送訊息給父視窗,將 this 指標作為 WPARAM 傳遞。ON_MESSAGE 對映處理函數,接收訊息後執行 delete。// 對話框類別
void CTestDlg2::OnDestroy()
{
CDialog::OnDestroy();
m_pParent->PostMessage(WM_DELETE_DLG, (WPARAM)this);
}
// 父視窗類別
afx_msg LONG OnDelDlgMsg(WPARAM wP, LPARAM lP);
ON_MESSAGE(WM_DELETE_DLG, OnDelDlgMsg)
LONG CMyView::OnDelDlgMsg(WPARAM wP, LPARAM lP)
{
delete (CTestDlg2*)wP;
return 0;
}
此法善用 Windows 訊息機制解耦物件生命週期,符合事件驅動程式設計慣例。
無模式對話框另一優勢在於能即時將使用者輸入同步至其他視窗。例如:使用者在對話框編輯文字,按下按鈕後透過 SendMessage() 將資料指標傳送給檢視視窗,檢視視窗接收訊息更新顯示內容並呼叫 Invalidate() 重繪。
// 對話框端
void CTestDlg2::OnCommBtn()
{
char szOut[30];
GetDlgItemText(IDC_OUT, szOut, 30);
m_pParent->SendMessage(WM_DLG_NOTIFY, (WPARAM)szOut);
}
// 檢視視窗端
ON_MESSAGE(WM_DLG_NOTIFY, OnDlgNotifyMsg)
LONG CMyView::OnDlgNotifyMsg(WPARAM wP, LPARAM lP)
{
m_szOut = (char*)wP;
Invalidate();
return 0;
}
此模式展示了無模式對話框作為「浮動工具面板」的典型用法,廣泛應用於屬性設定、即時預覽等場景。
無模式對話框的核心難點在於物件生命週期管理。本文提出的兩種策略——「自我銷毀」與「父視窗代管」——分別適合獨立運作與集中管理的架構需求。搭配訊息機制實現跨視窗資料同步,可構建靈活、響應迅速的使用者介面。掌握這些技巧,能讓 MFC 開發者更從容地處理複雜視窗交互邏輯。