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

ActiveX 控制項整合對話框技術:模態/非模態/子視窗三種模式完整實作指南

     編輯:關於C語言

為什麼在 ActiveX 中使用對話框?

ActiveX 控制項本身是無視窗或有視窗的 COM 物件。複雜 UI (設定面板、精靈、資料輸入) 直接在 OnDraw 繪製極其困難。MFC CDialog 提供完整的**資源編輯器設計、DDX/DDV、訊息映射、控制項管理**,將對話框作為控制項的**子視窗**或**獨立彈出視窗**嵌入,是標準做法。

模式一:模態對話框 (DoModal) - 同步阻塞

適用場景

  • 使用者必須完成操作才能繼續 (設定精靈、登入、確認對話框)。
  • 方法呼叫者預期同步返回結果。

實作步驟

  1. 資源編輯器新增對話框範本 IDD_MYDIALOG。
  2. ClassWizard 建立類別 CMyDialog : public CDialog。
  3. 控制項類別 CMyCtrl : public COleControl 成員加入 CMyDialog m_dlg; (或指標)。
  4. 自動化方法實作:

void CMyCtrl::DoModalDialog()
{
    // 直接呼叫 DoModal,阻塞直到使用者關閉
    m_dlg.DoModal(); // 此處可檢查返回值 IDOK/IDCANCEL
}

注意:m_dlg 為成員變數,生命週期隨控制項。DoModal 內部會建立臨時視窗,銷毀時自動清理。

模式二:非模態對話框 - 異步並存

適用場景

  • 工具面板、屬性檢視器、即時監控視窗,使用者可自由切換。
  • 控制項需持續顯示並接收事件。

實作步驟

  1. 同樣建立 CMyDialog m_dlg; 成員。
  2. 在控制項 OnCreate 中建立對話框視窗:

int CMyCtrl::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (COleControl::OnCreate(lpCreateStruct) == -1) return -1;

    // 建立非模態對話框 (WS_CHILD | WS_VISIBLE)
    if (!m_dlg.Create(IDD_MYDIALOG, this)) // this 為父視窗 (控制項視窗)
        return -1;

    return 0;
}

void CMyCtrl::ShowDialog()
{
    m_dlg.ShowWindow(SW_SHOW); // 顯示
    m_dlg.SetFocus();          // 可選:取得焦點
}

void CMyCtrl::HideDialog()
{
    m_dlg.ShowWindow(SW_HIDE);
}

關鍵點:

  • Create 而非 DoModal,返回 BOOL 而非阻塞。
  • 父視窗傳 this (控制項視窗),確保 Z-Order、剪裁、銷毀連動。
  • 控制項銷毀時 (OnDestroy) 需 m_dlg.DestroyWindow() 釋放視窗資源。

模式三:以對話框作為控制項主視窗 (Child Window) - 無框架嵌入

適用場景

  • 控制項本身就是一個複雜表單 (資料輸入、儀表板),無需額外彈出。
  • 容器 (IE、VB、VC 對話框) 直接顯示控制項客戶區即為對話框內容。

對話框範本屬性設定 (關鍵!)

控制項類別整合


class CMyCtrl : public COleControl
{
    // ...
    CMyDialog m_dlg; // 成員

protected:
    // 重載 OnCreateControl (ActiveX 控制項建立完畢後呼叫)
    virtual BOOL OnCreateControl()
    {
        if (!COleControl::OnCreateControl()) return FALSE;

        // 建立對話框作為子視窗,父視窗為控制項本身 (m_hWnd)
        if (!m_dlg.Create(IDD_MYDIALOG, this))
            return FALSE;

        // 調整對話框大小填滿控制項客戶區
        CRect rc; GetClientRect(&rc);
        m_dlg.MoveWindow(&rc);
        m_dlg.ShowWindow(SW_SHOW);

        return TRUE;
    }

    // 處理控制項大小變更
    virtual void OnSize(UINT nType, int cx, int cy)
    {
        COleControl::OnSize(nType, cx, cy);
        if (m_dlg.GetSafeHwnd())
            m_dlg.MoveWindow(0, 0, cx, cy);
    }
};

進階:對話框與控制項通訊

屬性頁設定值原因
Styles → StyleChild作為子視窗嵌入,無標題列、邊框
Styles → BorderNone (或 Dialog Frame 視需求)無邊框
Styles → Title BarUnchecked無標題列
More Styles → VisibleChecked建立即顯示
More Styles → ControlChecked支援 Tab 鍵導航、Dialog 鍵盤介面
Extended Styles → Static EdgeChecked (可選)輕微 3D 邊框效果
方向機制範例
控制項 → 對話框直接呼叫對話框 public 方法 / 設定 public 成員m_dlg.SetData(pData);
對話框 → 控制項對話框建構時傳 CMyCtrl* pCtrl,或 GetParent() 轉型((CMyCtrl*)GetParent())->FireEvent(...);
對話框控制項事件對話框類別內正常訊息映射 (ON_BN_CLICKED 等)按鈕點擊 → 對話框處理 → 通知控制項觸發事件

資源清理與銷毀順序


void CMyCtrl::OnDestroy()
{
    if (m_dlg.GetSafeHwnd())
        m_dlg.DestroyWindow(); // 先銷毀子視窗
    COleControl::OnDestroy();
}

// 或在非模態模式下,對話框成員為指標
CMyDialog* m_pDlg = nullptr;
int OnCreate(...) {
    m_pDlg = new CMyDialog;
    m_pDlg->Create(IDD, this);
    return 0;
}
void OnDestroy() {
    if (m_pDlg) { m_pDlg->DestroyWindow(); delete m_pDlg; m_pDlg = nullptr; }
    COleControl::OnDestroy();
}

常見坑與解決

  • Tab 鍵不工作:對話框範本 **More Styles → Control** 必須勾選;控制項需實作 IOleInPlaceActiveObject::TranslateAccelerator 轉發鍵盤訊息 (MFC COleControl 預設已處理)。
  • 對話框不隨控制項縮放:覆寫 OnSize 調用 MoveWindow。
  • 模態對話框阻塞容器:IE 中模態對話框會凍結瀏覽器,慎用;改用非模態或模擬模態 (Disable 父視窗)。
  • 資源 ID 衝突:DLL 中對話框資源 ID 需唯一,使用 AFX_MANAGE_STATE 確保正確載入 DLL 資源。

總結

ActiveX 控制項整合對話框三大模式:**模態** (同步阻塞、簡單)、**非模態** (並存、工具面板)、**子視窗嵌入** (無框架、控制項即表單)。核心在於對話框範本屬性正確設定 (Child/No Border/Control)、父視窗關係正確 (控制項視窗)、生命週期同步 (Create/DestroyWindow)、鍵盤導航支援。掌握此技術,可將複雜 MFC 對話框 UI 封裝為可重用、跨容器部署的 ActiveX 控制項。

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