| 特性 | 有模式對話框 | 無模式對話框 |
|---|---|---|
| 建立函式 | DoModal() | Create() + ShowWindow() |
| 程式流程 | 阻塞呼叫執行緒,直到關閉 | 立即返回,主視窗繼續運作 |
| 物件壽命 | 通常用區域變量(棧上) | 需動態配置(堆上),手動銷毀 |
| 父視窗關係 | 自動停用父視窗 | 父視窗保持啟用,可並行操作 |
void CYourView::OnOpenModelessDlg()
{
// 1. 堆上建立對話框物件
CTestDlg* pDlg = new CTestDlg;
// 2. 從資源範本建立視窗(尚未顯示)
if (!pDlg->Create(IDD_TEST_DLG, this)) // this 為父視窗指標
{
delete pDlg; // 建立失敗需手動釋放
return;
}
// 3. 顯示視窗
pDlg->ShowWindow(SW_SHOW);
// 4. 【關鍵】不要在此處 delete pDlg!
// 物件由對話框內部自行銷毀(見下文)
}
無模式對話框物件必須在視窗銷毀時自我刪除,兩種主流模式:
// CTestDlg.h
class CTestDlg : public CDialog
{
DECLARE_MESSAGE_MAP()
public:
afx_msg void OnOK();
afx_msg void OnCancel();
afx_msg void OnDestroy();
};
// CTestDlg.cpp
BEGIN_MESSAGE_MAP(CTestDlg, CDialog)
ON_WM_DESTROY()
END_MESSAGE_MAP()
void CTestDlg::OnOK()
{
CDialog::OnOK(); // 執行預設行為(UpdateData 等)
DestroyWindow(); // 強制銷毀視窗,觸發 WM_DESTROY
}
void CTestDlg::OnCancel()
{
CDialog::OnCancel();
DestroyWindow();
}
void CTestDlg::OnDestroy()
{
CDialog::OnDestroy();
delete this; // 【核心】自我刪除 C++ 物件
}
// 父視窗類別(如 CMainFrame 或 CView)
class CParentWnd : public CFrameWnd
{
CTestDlg* m_pModelessDlg; // 成員指標
// ...
};
void CParentWnd::OnOpenDlg()
{
if (m_pModelessDlg == nullptr)
{
m_pModelessDlg = new CTestDlg;
m_pModelessDlg->Create(IDD_TEST_DLG, this);
m_pModelessDlg->ShowWindow(SW_SHOW);
}
else
{
m_pModelessDlg->SetForegroundWindow(); // 已存在則帶到前景
}
}
// 父視窗關閉時清理
void CParentWnd::OnClose()
{
if (m_pModelessDlg)
{
m_pModelessDlg->DestroyWindow(); // 觸發對話框 OnDestroy
m_pModelessDlg = nullptr; // 指標置空,防止野指標
}
CFrameWnd::OnClose();
}
// 對話框 OnDestroy 僅置空父視窗指標,不自刪
void CTestDlg::OnDestroy()
{
CDialog::OnDestroy();
// 通知父視窗(可用 PostMessage 自訂訊息)
GetParent()->PostMessage(WM_USER_DLG_CLOSED, 0, (LPARAM)this);
// 不要 delete this!
}
| 函式 | 用途 | 備註 |
|---|---|---|
Create(lpTemplateName, pParentWnd) | 建立視窗(不顯示) | 資源 ID 或範本指標 |
ShowWindow(nCmdShow) | 顯示/隱藏視窗 | SW_SHOW/SW_HIDE |
DestroyWindow() | 銷毀視窗,發送 WM_DESTROY | 非同步,立即返回 |
IsWindow(m_hWnd) | 檢查視窗是否存在 | 避免對已銷毀物件操作 |
SetForegroundWindow() | 帶到前景並啟用 | 適用單一實例模式 |
new 動態配置。NULL:對話框會游離於工作列,無法隨主視窗最小化/還原。請傳 this 或 AfxGetMainWnd()。if (m_pDlg == nullptr) 或 IsWindow(m_pDlg->m_hWnd)。PostMessage 通信。new 出的子物件,需在 OnDestroy 或解構子釋放。資源編輯器中設定對話框屬性:
// 父視窗 OnCreate 中嵌入
int CParentView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1) return -1;
m_pChildDlg = new CChildDlg;
m_pChildDlg->Create(IDD_CHILD_DLG, this);
m_pChildDlg->SetWindowPos(nullptr, 0, 0, 400, 300, SWP_NOZORDER | SWP_SHOWWINDOW);
return 0;
}
// 父視窗大小改變時調整子對話框
void CParentView::OnSize(UINT nType, int cx, int cy)
{
CView::OnSize(nType, cx, cy);
if (m_pChildDlg && ::IsWindow(m_pChildDlg->m_hWnd))
m_pChildDlg->MoveWindow(0, 0, cx, cy);
}