小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

VC6中使用CHtmlView在對話框控制中顯示HTML文件

 imzjw 2010-01-06

編譯/趙湘寧

 



本文的例子程序


    在Visual Studio 6.0中出現(xiàn)了一個新類CHtmlView,利用這個類,我們可以實現(xiàn)在對話框的控制中顯示HTML文件。 要想使用CHtmlView類,對它的定義和實現(xiàn)就必須有全面深入的理解。我們不妨拿CHtmlView和CListView做一個比較,通過比較這兩個類,我們會發(fā)現(xiàn)一些有趣的差別。首先,MFC中CListView有一個對應(yīng)的CListCtrl類,而CHtmlView卻沒有一個CHtmlCtrl類與之對應(yīng);其次,CListView的使用依賴于MFC的文檔/視結(jié)構(gòu),而CHtmlView的實現(xiàn)是基于COM的。通過IWebBrowser2接口來實現(xiàn),而且IWebBrowser2與MFC文檔/視圖結(jié)構(gòu)之間沒有任何關(guān)系。
為了實現(xiàn)在對話框的控制中顯示HTML文件,我們也可以為CHtmlView創(chuàng)建一個對應(yīng)的類CHtmlCtrl。以下是類CHtmlCtrl程序源代碼
創(chuàng)建一個靜態(tài)控制(也可以是其他控制),這個控制的ID及大小位置與界面上的控制相同。
BOOL CHtmlCtrl::CreateFromStatic(UINT nID, CWnd* pParent)
{
CStatic wndStatic;
if (!wndStatic.SubclassDlgItem(nID, pParent))
return FALSE;
// 獲取靜態(tài)控制的矩形區(qū)域并轉(zhuǎn)換為父窗口的客戶區(qū)坐標
CRect rc;
wndStatic.GetWindowRect(&rc);
pParent->ScreenToClient(&rc);
wndStatic.DestroyWindow();
// 創(chuàng)建 HTML 控制 (CHtmlView)
return
Create(NULL,		                    // 類名
NULL,		                    // 標題
(WS_CHILD | WS_VISIBLE ),		 // 風格
rc,				 // 矩形區(qū)域
pParent,			          // /父窗口
nID,				  // 控制 ID
NULL);			          ///框架/文檔
}
    為了避免主控程序?qū)HtmlView對象看作是文檔/視圖框架,需要重載,CView::OnMouseActivate和CView::OnDestroy。此外,當用戶在控制中單擊時,OnMouseActivate要負責響應(yīng)(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()中釋放空間,但對話框中的控制常常是作為堆棧對象實現(xiàn)的,所以,在PostNcDestroy()中不必在做什么。
     virtual void PostNcDestroy() {  }     
為了實現(xiàn)“app:” 偽協(xié)議,重載導(dǎo)航處理器OnBeforeNavigate2()。傳遞“app:”鏈接到一個虛擬協(xié)議處理器。因為app:是假協(xié)議,所以在瀏覽起重要取消掉這個導(dǎo)航。
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:命令,當瀏覽器準備導(dǎo)航到“app:foo”時,這個函數(shù)被調(diào)用,參數(shù)lpszWhere的值為“foo”。
void CHtmlCtrl::OnAppCmd(LPCTSTR lpszWhere){ // default: do nothing}
    重載OnMouseActivate, OnDestroy, 和 PostNcDestroy以后,CHtrmlCtrl在對話框中就可以象個控制一樣工作。詳細的使用方法請參見例子程序:AboutHtml。 運行AboutHtml.exe,并打開About對話框……音樂多么美妙!更有趣的是程序所用到的HTML源文件、圖像、聲音等文件都作為資源存儲在EXE文件中:
// in AboutHtml.rc
ABOUT.HTM  HTML DISCARDABLE "res\\about.htm"
PD.JPG     HTML DISCARDABLE "res\\pd.jpg"
OKUP.GIF   HTML DISCARDABLE "res\\okup.gif"
OKDN.GIF   HTML DISCARDABLE "res\\okdn.gif"
MOZART.WAV HTML DISCARDABLE "res\\mozart.wav"        
    注意:用文件的實際名字作為資源名很重要,以便瀏覽器能夠找到他們。在一個普通的Web頁面中,我們使用圖像是用下列語法:
 <IMG src="pd.jpg">
    此代碼假設(shè)圖像文件"pd.jpg"存在當前目錄(頁面文件所在目錄)中。
如果圖像文件是作為資源存在EXE文件中,我們?nèi)绾我媚??方法一樣,此時,我們必須告訴瀏覽器Web頁面文件的位置。為此要在Web頁面文件的開頭加上如下代碼:
<BASE url="res://AboutHtml.exe/about.htm">
    這一行代碼告訴瀏覽器當前目錄是“res://AboutHtml.exe”,當瀏覽器遇到代碼<IMG src="pd.jpg">時,它會按照路徑res://AboutHtml.exe/pd.jpg查找。否則,它會在程序文件的路徑查找。
    通常用res://modulename可以訪問動態(tài)庫或可執(zhí)行文件中的資源。這里res:的意思與http:,ftp:,file:,及mailto的意思相同。即:“在這個路徑中的第一個名字是一個文件名,第二個名字是文件中的資源名”。其余的工作由瀏覽器完成。
    為了實現(xiàn)About對話框,先建一個對話框類:CAboutDialog,其中聲明一個CHtmlCtrl對象:m_page。CAboutDialog本身的初始化代碼如下:
BOOL CAboutDialog::OnInitDialog()
{
VERIFY(CDialog::OnInitDialog());
VERIFY(m_page.CreateFromStatic(IDC_HTMLVIEW, this));
m_page.LoadFromResource(_T("about.htm"));
return TRUE;
}

    CHtmlCtrl::CreateFromStatic是個很簡單的函數(shù),它用于簡化對話框的設(shè)計。因為用插入COM對象的方法太麻煩,所以我在對話框中插入了一個靜態(tài)控件,改變它的缺省ID號。然后調(diào)用CreateFromStatic,以完全相同的ID號、大小、位置創(chuàng)建一個靜態(tài)CStatic對象。然后在調(diào)用DestroyWindow,這個方法很有效。為了加載web頁面,調(diào)用CHtmlCtrl::LoadFromResource函數(shù),它是由CHtmlView繼承而來的。也可以用全路徑res://AboutHtml.exe/about.htm作為參數(shù)。
現(xiàn)在您已經(jīng)知道了CHtmlCtrl是如何在對話框中繞過CView來替代框架;知道了如何創(chuàng)建HTML文件,其中包含文字、圖像和聲音,并把它作為資源在程序中使用。
    除此之外,還有一個問題就是:CAboutDialog對話框中“OK”按鈕的處理,其實,它根本就不是一個按鈕,而是一個在HTML文件中嵌入的圖像,用JScript來控制圖像被按下時和彈起時的狀態(tài)。處理“OK”按鈕的技巧主要是解決對話框與主控程序之間的通訊。
    利用動態(tài)HTML文檔層(COM)技術(shù)可以處理用戶單擊圖像或鏈接,方法是獲得圖像元素,然后偵聽OnClick事件。但這是一種非常非常麻煩的方法。有沒有更簡單的方法呢……對于編程者來說,懶惰是一種美德。
假設(shè)HTML有如下的圖像鏈接:

<A href="ok"><IMG ...></A>        
     當用戶單擊它時,瀏覽器顯示這個“OK”文件,但是在顯示之前,控制先執(zhí)行CHtmlCtrl::OnBeforeNavigate2。CHtmlCtrl能夠在這個函數(shù)中做想做的任何事情。
void CMyHtmlCtrl::OnBeforeNavigate2(
LPCTSTR lpszURL,
...,
BOOL* pbCancel)
{
if (_tcscmp(lpszURL,_T("ok"))==0)
{
// "ok" clicked:
*pbCancel=TRUE; // abort 
// will close dialog 
GetParent()->SendMessage(WM_COMMAND,IDOK);
}
}
    其實“OK”并不是什么文件;它只是一個很特殊的名字,CHtmlCtrl將它看作是“OK”按鈕。為了實現(xiàn)這個想法,程序中創(chuàng)建了一個叫app:的冒充協(xié)議來代替“OK”,在about.htm中實際的鏈接是app:ok。每當瀏覽器導(dǎo)航到app:somewhere的時候,CHtmlCtrl都以“somewhere”為參數(shù)調(diào)用一個虛函數(shù):CHtmlCtrl::OnAppCmd。
void CMyHtmlCtrl::OnAppCmd( LPCTSTR lpszWhere )
{
if (_tcsicmp(lpszWhere, _T("ok"))==0)
{
GetParent()->SendMessage(WM_COMMAND,IDOK);
}
}
    您可以在HTML文件中作其他的鏈接,諸如:app:cancel, app:refresh, 或 app:whatever等等,并且在OnAppCmd中編寫自己的代碼來處理 “cancel”、“refresh”、和“whatever” 、 字符串,它有點象在VB中編程。
    參照例子程序,將自己的About對話框改進一番吧。如果有興趣的話,您甚至可以利用這個技術(shù)來實現(xiàn)復(fù)活節(jié)彩蛋。
 
 
 
附錄一:CHtmlCtrl類的定義和實現(xiàn)
//定義文件
HtmlCtrl.h
//
class CHtmlCtrl : public CHtmlView {
public:
CHtmlCtrl() { }
~CHtmlCtrl() { }
BOOL CreateFromStatic(UINT nID, CWnd* pParent);
// Normally, CHtmlView destroys itself in PostNcDestroy,
// but we don't want to do that for a control since a control
// is usually implemented as a stack object in a dialog.
//
virtual void PostNcDestroy() {  }
// overrides to bypass MFC doc/view frame dependencies
afx_msg void OnDestroy();
afx_msg int  OnMouseActivate(CWnd* pDesktopWnd,UINT nHitTest,UINT message);
// override to trap "app:" pseudo protocol
virtual void OnBeforeNavigate2( LPCTSTR lpszURL,
DWORD nFlags,
LPCTSTR lpszTargetFrameName,
CByteArray& baPostedData,
LPCTSTR lpszHeaders,
BOOL* pbCancel );
// override to handle links to "app:mumble...". lpszWhere will be "mumble"
virtual void OnAppCmd(LPCTSTR lpszWhere);
DECLARE_MESSAGE_MAP();
DECLARE_DYNAMIC(CHtmlCtrl)
};
//實現(xiàn)文件
HtmlCtrl.cpp
//
#include "StdAfx.h"
#include "HtmlCtrl.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
IMPLEMENT_DYNAMIC(CHtmlCtrl, CHtmlView)
BEGIN_MESSAGE_MAP(CHtmlCtrl, CHtmlView)
ON_WM_DESTROY()
ON_WM_MOUSEACTIVATE()
END_MESSAGE_MAP()
//////////////////
// Create control in same position as an existing static control with
// the same ID (could be any kind of control, really)
//
BOOL CHtmlCtrl::CreateFromStatic(UINT nID, CWnd* pParent)
{
CStatic wndStatic;
if (!wndStatic.SubclassDlgItem(nID, pParent))
return FALSE;
// Get static control rect, convert to parent's client coords.
CRect rc;
wndStatic.GetWindowRect(&rc);
pParent->ScreenToClient(&rc);
wndStatic.DestroyWindow();
// create HTML control (CHtmlView)
return Create(NULL,                  // class name
NULL,                             // title
(WS_CHILD | WS_VISIBLE ),         // style
rc,                               // rectangle
pParent,                          // parent
nID,                              // control ID
NULL);                            // frame/doc context not used
}
////////////////
// Override to avoid CView stuff that assumes a frame.
//
void CHtmlCtrl::OnDestroy()
{
// This is probably unecessary since ~CHtmlView does it, but
// safer to mimic CHtmlView::OnDestroy.
if (m_pBrowserApp) {
m_pBrowserApp->Release();
m_pBrowserApp = NULL;
}
CWnd::OnDestroy(); // bypass CView doc/frame stuff
}
////////////////
// Override to avoid CView stuff that assumes a frame.
//
int CHtmlCtrl::OnMouseActivate(CWnd* pDesktopWnd, UINT nHitTest, UINT msg)
{
// bypass CView doc/frame stuff
return CWnd::OnMouseActivate(pDesktopWnd, nHitTest, msg);
}
//////////////////
// Override navigation handler to pass to "app:" links to virtual handler.
// Cancels the navigation in the browser, since app: is a pseudo-protocol.
//
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;
}
}
void CHtmlCtrl::OnAppCmd(LPCTSTR lpszWhere)
{
// default: do nothing
}

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多