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

MFC 無模式對話框建立與銷毀生命週期深度解析

     編輯:VC 教學

前言

無模式對話框 (CDialog::Create) 與模態對話框 (DoModal) 生命週期管理迥異。模態對話框由框架自動銷毀,無模式對話框則需開發者手動管理物件銷毀時機。錯誤的管理易導致記憶體洩漏、存取違規或資源未釋放。本文透過完整範例剖析兩種主流銷毀策略。

基本建立與顯示流程

void CMyView::OnOpenDlg()
{
    CTestDlg* dlg = new CTestDlg;        // 1. 堆疊配置物件
    dlg->Create(IDD_TEST_DLG, NULL);     // 2. 建立視窗 (非模態)
    dlg->ShowWindow(SW_SHOW);            // 3. 顯示視窗
    // 此處不可 delete dlg!視窗仍在顯示中
}

關鍵:物件必須在堆疊上配置 (new),且不在建立函式中刪除。

策略一:對話框自我銷毀 (Self-Destruction)

在對話框類別內覆寫 OnOK、OnCancel、OnDestroy:

void CTestDlg1::OnOK()
{
    CDialog::OnOK();
    DestroyWindow(); // 觸發 WM_DESTROY
}

void CTestDlg1::OnCancel()
{
    CDialog::OnCancel();
    DestroyWindow();
}

void CTestDlg1::OnDestroy()
{
    CDialog::OnDestroy();
    AfxMessageBox(_T("call delete this"));
    delete this; // 關鍵:視窗銷毀時刪除自身物件
}

優點:封裝性好,呼叫端無需追蹤指標。
缺點:delete this 需極度小心,確保之後不再存取任何成員。

策略二:父視窗負責銷毀 (Parent-Managed)

對話框建立時傳遞父視窗指標,銷毀時發送自訂訊息通知父視窗刪除物件。

對話框類別 (CTestDlg2)

CTestDlg2::CTestDlg2(CWnd* pParent)
    : CDialog(IDD, pParent), m_pParent(pParent)
{
    ASSERT(pParent); // 父視窗指標必須有效且非暫時性
}

void CTestDlg2::OnOK() { CDialog::OnOK(); DestroyWindow(); }
void CTestDlg2::OnCancel() { CDialog::OnCancel(); DestroyWindow(); }

void CTestDlg2::OnDestroy()
{
    CDialog::OnDestroy();
    // 發送自訂訊息給父視窗,傳遞自身指標
    m_pParent->PostMessage(WM_DELETE_DLG, (WPARAM)this);
}

父視窗類別 (CMyView)


// 標頭檔
afx_msg LONG OnDelDlgMsg(WPARAM wParam, LPARAM lParam);

// 訊息映射
ON_MESSAGE(WM_DELETE_DLG, OnDelDlgMsg)

// 實作
LONG CMyView::OnDelDlgMsg(WPARAM wParam, LPARAM lParam)
{
    delete (CTestDlg2*)wParam; // 刪除對話框物件
    return 0;
}

// 建立對話框
void CMyView::OnTest2()
{
    CTestDlg2* dlg = new CTestDlg2(this); // 傳遞 this 作為父視窗
    dlg->Create(IDD_TEST_DLG_2);
    dlg->ShowWindow(SW_SHOW);
}

優點:物件擁有權清晰歸屬父視窗,避免 delete this 風險。
缺點:父視窗需定義訊息處理,略增複雜度。

進階應用:無模式對話框即時回傳資料

利用訊息機制將使用者輸入即時傳遞給父視窗:

// 對話框中按鈕處理
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 wParam, LPARAM lParam)
{
    m_szOut = (char*)wParam; // 保存字串指標 (注意生命週期)
    Invalidate();            // 觸發重繪
    return 0;
}

// OnDraw 中顯示
void CMyView::OnDraw(CDC* pDC)
{
    pDC->TextOut(0, 0, _T("Display String"));
    pDC->TextOut(0, 20, m_szOut);
}

注意:以 SendMessage 同步傳遞指標需確保緩衝區在對話框銷毀前有效,或改用 PostMessage 配合字串複製。

常見錯誤與最佳實務

錯誤後果正確做法
棧上配置對話框物件函式返回物件銷毀,視窗句柄失效使用 new 堆疊配置
建立後未呼叫 ShowWindow視窗不可見必須呼叫 ShowWindow(SW_SHOW)
在建立函式中 delete視窗尚未顯示即銷毀在 OnDestroy 或父視窗訊息中刪除
delete this 後繼續存取成員未定義行為/崩潰delete this 必須是最後一行執行碼
父視窗指標為暫時物件發送訊息時指標失效父視窗必須為長生命週期物件 (如 View、Frame)

結語

無模式對話框賦予介面極大靈活性,但要求開發者精確掌控物件生命週期。採用「自我銷毀」或「父視窗管理」兩種經典模式,配合訊息機制實現資料雙向流動,是 MFC 開發的核心技能之一。

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