在VC對話框中用ChtmlView控件顯示"HTML"

導讀:
微軟的MFC在Visual Studio 6.0中提供了一個新類CHtmlView,利用這個類,我們可以實現在基於文檔視圖結構的程序中顯示HTML文件。 但是它是否可以用來在對話框中實現這一功能呢?我們不妨拿CHtmlView和CListView做一個比較,通過比較這兩個類,我們會發現一些有趣的差別,MFC中CListView有一個對應的CListCtrl類用來在對話框中使用,而CHtmlView卻沒有一個CHtmlCtrl類與之對應。所以爲了實現在對話框的控制中顯示HTML文件,我們不得不爲CHtmlView創建一個對應的子類CHtmlCtrl。爲了演示該類的使用方法,本實例在程序的About對話框中顯示一個名爲"about.htm"的HTML文件。更有趣的是,程序所用到的HTML源文件是作爲資源存儲在EXE文件中的。該程序編譯運行後的效果如圖一所示:
642856153.jpg

圖一、顯示HTML文件的對話框
  一、實現方法
  爲了在對話框中顯示HTML文件,我們必須將CHtmlCtrl類與對話框中的一個靜態控制(也可以是其它控制)關聯起來,這樣才能爲顯示HTML文件提供一個窗口,爲此我們在CHtmlCtrl類中定義了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();
 // 創建 HTML 控制 (CHtmlView)
 return (Create(NULL, // 類名;
  NULL, // 標題;
  (WS_CHILD | WS_VISIBLE ), // 風格;
  rc, // 矩形區域;
  pParent, // 父窗口;
  nID, // 控制的ID號;
  NULL)); //取消文檔框架支持;
}
  爲了避免主控程序將CHtmlView對象看作是文檔/視圖框架,需要重載CView::OnMouseActivate()和CView::OnDestroy()函數。此外,當用戶在控制中單擊時,OnMouseActivate要負責響應(WM_MOUSEACTIVATE)。
int CHtmlCtrl::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT msg)
{
 //旁路 CView 文檔/框架
 return CWnd::OnMouseActivate(pDesktopWnd, nHitTest, msg);
}
void CHtmlCtrl::OnDestroy()
{
 if (m_pBrowserApp)
 {
  m_pBrowserApp->Release();
  m_pBrowserApp = NULL;
 }
 CWnd::OnDestroy(); // 旁路 CView 文檔/框架
}
  通常,CHtmlView是在virtual void PostNcDestroy()中釋放空間,但對話框中的控制常常是作爲堆棧對象實現的,所以,在PostNcDestroy()中不必在做什麼。
  爲了播放資源中的HTML文件,需要重載導航處理器OnBeforeNavigate2(), 實現"app:" 僞協議,。傳遞"app:"鏈接到一個虛擬協議處理器。因爲app:是假協議,所以需要設置pbCancel參數爲"TRUE",以停止掉這個導航。
void CHtmlCtrl::OnBeforeNavigate2( LPCTSTR lpszURL,
DWORD nFlags,
LPCTSTR lpszTargetFrameName,
CByteArray& baPostedData,
LPCTSTR lpszHeaders,
BOOL* pbCancel )
{
 const char APP_PROTOCOL[] = "app:";
 int len = _tcslen(APP_PROTOCOL);
 if (_tcsnicmp(lpszURL, APP_PROTOCOL, len)==0)
 {
  OnAppCmd(lpszURL + len);
  *pbCancel = TRUE;
 }
}
  定義一個虛函數OnAppCmd(),處理app:命令,例如當瀏覽器準備導航到"app:foo"時,這個函數被調用,參數lpszWhere的值爲"foo"。
void CHtmlCtrl::OnAppCmd(LPCTSTR lpszWhere){ // default: do nothing}
  對於作爲資源的HTML文件和其中的嵌入的圖片和音樂文件,用文件的實際名字作爲資源名很重要,以便瀏覽器能夠找到他們。在一個普通的Web頁面中,我們使用圖像是用下列語法:
pd.jpg
  此代碼假設圖像文件"pd.jpg"存在當前目錄(頁面文件所在目錄)中。如果圖像文件是作爲資源存在EXE文件中,我們如何引用呢?方法一樣,此時,我們必須告訴瀏覽器Web頁面文件的位置。爲此要在Web頁面文件的開頭加上如下代碼:

  這一行代碼告訴瀏覽器當前目錄是"res://ShowHtml.exe",當瀏覽器遇到代碼pd.jpg時,它會按照路徑res://ShowHtml.exe/pd.jpg查找。否則,它會在程序文件的路徑查找。通常用res://modulename可以訪問動態庫或可執行文件中的資源。這裏res:的意思與http:,ftp:,file:,及mailto的意思相同。即:"在這個路徑中的第一個名字是一個文件名,第二個名字是文件中的資源名"。其餘的工作由瀏覽器完成。
  爲了在對話框中加載web頁面,調用CHtmlCtrl::LoadFromResource函數,它是由CHtmlView繼承而來的。也可以用全路徑res://ShowHtml.exe/about.htm作爲參數。除此之外,還有一個問題就是:CAboutDialog對話框中"OK"按鈕的處理,其實,它根本就不是一個按鈕,而是一個在HTML文件中嵌入的圖像,用JScript來控制圖像被按下時和彈起時的狀態。處理"OK"按鈕的技巧主要是解決對話框與主控程序之間的通訊。利用動態HTML文檔層(COM)技術可以處理用戶單擊圖像或鏈接,方法是獲得圖像元素,然後偵聽OnClick事件。但這是一種非常非常麻煩的方法。還有一種更簡單的方法。假設HTML有如下的圖像鏈接:

  當用戶單擊它時,瀏覽器顯示這個"OK"文件,但是在顯示之前,控制先執行CHtmlView::OnBeforeNavigate2()函數,爲此可以定義CHtmlCtrl類的子類CMyHtmlCtrl,重載這個函數,在這裏面實現想做的任何事情。下面的代碼實現了當用戶點擊HTML文件上的"OK"圖片時,關閉對話框。
void CHtmlCtrl::OnBeforeNavigate2(
 LPCTSTR lpszURL,
 ...,
 BOOL* pbCancel)
{
 if (_tcscmp(lpszURL,_T("ok"))==0)
 {
  // "ok" clicked:
  *pbCancel=TRUE; // abort
  GetParent()->SendMessage(WM_COMMAND,IDOK); // will close dialog
 }
}
  其實"OK"並不是什麼文件;它只是一個很特殊的名字,可以定義一個CHtmlCtrl類的子類CMyHtmlCtrl,該類將"OK"圖片看作是"OK"按鈕。爲了實現這個想法,程序中創建了一個叫app:的冒充協議來代替"OK",在about.htm中定義實際的鏈接是app:ok。每當瀏覽器導航到app:somewhere的時候,CMyHtmlCtrl都以"somewhere"爲參數調用一個虛函數:CMyHtmlCtrl::OnAppCmd。
void CMyHtmlCtrl::OnAppCmd( LPCTSTR lpszWhere )
{
 if (_tcsicmp(lpszWhere, _T("ok"))==0)
 {
  GetParent()->SendMessage(WM_COMMAND,IDOK);
 }
}
  二、編程步驟
  1、啓動Visual C++6.0,生成一個單文檔的應用程序,命名爲"ShowHtml";
  2、修改程序中的"About"對話框資源,在其中放置一個Static控件,設置它的ID爲IDC_HTMLVIEW;
  3、向程序中添加HTML文件資源,其ID設置爲"About.htm";
  4、向程序中添加CHtmlCtrl、CMyHtmlCtrl類文件;
  5、在CAbout類中增加一個CMyHtmlCtrl類的對象m_page,並使用CLASSWIZARD重載CAbout類的OnInitDialog()函數;
  6、編譯運行程序。

本文轉自
http://tech.sina.com.cn/s/2006-01-13/0803819204.shtml
發佈了21 篇原創文章 · 獲贊 1 · 訪問量 4萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章