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

MFC 實作 View 與 Frame 分離:打造可嵌入對話方塊的 CHtmlCtrl

     編輯:關於VC++

MFC 文檔/視圖架構將 View、Frame、Document 緊密綁定。若想將 CHtmlView 如同一般控制項般放入對話方塊,必須解決兩大難題:

  1. 如何讓最終產物 CHtmlCtrl 像 CButton 一樣隨意置入對話方塊?
  2. View 假設擁有 Frame,但控制項無 Frame 概念,需繞過 MFC 內部對 Frame 的依賴。

核心策略:以 CStatic 為代理子類化

利用 CStatic 控制項作為佔位符,透過 SubclassDlgItem 將其替換為 CHtmlCtrl,保持相同 ID、尺寸與位置。

CHtmlView 與 CHtmlCtrl 差異分析

本質相同,僅使用方式不同。View 專為文檔/視圖架構設計,擁有 m_pDocument 指標並固定於 CFrameWnd 中。但 m_pDocument 可為 NULL,CHtmlView 實際使用 IWebBrowser2,與 MFC 文檔架構無關。

關鍵衝突點與解決方案

1. CView::OnMouseActive

處理 WM_MOUSEACTIVE 時呼叫 GetParentFrame() 並啟動視圖,假設父視窗為 CFrameWnd。解決:覆寫直接呼叫 CWnd::OnMouseActive 繞過 Frame 邏輯。

2. CView::OnDestroy

銷毀時呼叫 GetParentFrame() 並停用視圖。解決:覆寫直接呼叫 CWnd::OnDestroy。

3. CView::PostNcDestroy

預設 delete this,適合堆積建立的 View,但控制項通常為父視窗成員變數,不應自我刪除。解決:覆寫為空實作。

int CHtmlCtrl::OnMouseActive(...) {
    return CWnd::OnMouseActive(...);  // 繞過 CView doc/frame 邏輯
}
void CHtmlCtrl::OnDestroy() {
    CWnd::OnDestroy();  // 繞過 CView doc/frame 邏輯
}
void CHtmlCtrl::PostNcDestroy() {
    // 不執行 delete this
}

實作範例:HTML 版 About 對話方塊

資源檔嵌入 HTML、圖片、音效:

ABOUT.HTML HTML DISCARDABLE "res\about.htm"
VCKBCOM.GIF HTML DISCARDABLE "res\vckcom.gif"
OKUP.GIF   HTML DISCARDABLE "res\okup.gif"
OKDN.GIF   HTML DISCARDABLE "res\okdn.gif"
MOZART.WAV HTML DISCARDABLE "res\mozart.wav"

HTML 中使用 res: 協定定位資源:

<BASE url="res://AboutHtml.exe/about.htm">
<IMG src="vckcom.gif">  <!-- 瀏覽器自動解析為 res://AboutHtml.exe/vckcom.gif -->

對話方塊初始化

BOOL CAboutDialog::OnInitDialog() {
    CDialog::OnInitDialog();
    VERIFY(m_page.CreateFromStatic(IDC_HTMLVIEW, this));
    m_page.LoadFromResource(_T("about.htm"));
    return TRUE;
}

CreateFromStatic 實作

BOOL CHtmlCtrl::CreateFromStatic(UINT nID, CWnd* pParent) {
    CStatic wndStatic;
    if (!wndStatic.SubclassDlgItem(nID, pParent)) return FALSE;
    CRect rc; wndStatic.GetWindowRect(&rc); pParent->ScreenToClient(&rc);
    wndStatic.DestroyWindow();
    return Create(NULL, NULL, WS_CHILD | WS_VISIBLE, rc, pParent, nID, NULL);
}

HTML 與應用程式互動:自訂協定 app:

OK 按鈕實為圖片連結 <A href="app:ok"><IMG ...></A>。點擊觸發 CHtmlCtrl::OnBeforeNavigate2,攔截 app: 協定並轉派虛擬函式 OnAppCmd:

void CMyHtmlCtrl::OnAppCmd(LPCTSTR lpszWhere) {
    if (_tcsicmp(lpszWhere, _T("ok")) == 0)
        GetParent()->SendMessage(WM_COMMAND, IDOK);
}

可擴充 app:cancel、app:refresh 等指令,實現豐富互動。

補充提示

  • IE DLL 載入需少許時間,避免 About 對話方塊顯示超過 10 秒造成等待不佳體驗。
  • 右鍵選單可透過 HTML <body oncontextmenu="return false"> 禁用,或以子類化方式攔截。

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