1. 程式人生 > >VC7 HTML Dialog開發例項講解

VC7 HTML Dialog開發例項講解

在VS7中添加了一種新的對話方塊類:CDHtmlDialog,顧名思義就是能夠顯示DHTML內容的對話方塊,但不同與以前的CHTMLView不同的是添加了對DHTML的支援,能夠響應各種DHTML的事件,而且能夠方便的得到網頁上的各種內容和輸入。在這以前要完成這些功能必須通過複雜的COM介面來完成,而現在MS MFC已經為我們做好了這一切。 
   在下面我會按照下面的順序講解CDHtmlDialog的用法。但本文也只能對DHTML對話方塊的功能進行部分的講解,更多更全的說明需要大家自己摸索和查詢資料。本文的目的是在於講解如何得到和設定網頁上的各種元素的值,如何處理事件。 
   此外在閱讀本文前你必須對HTML和DHTML有所瞭解。

類成員函式介紹 

   建構函式 

   CDHtmlDialog( ); 
   CDHtmlDialog( 
   LPCTSTR lpszTemplateName, 
   LPCTSTR szHtmlResID, 
   CWnd *pParentWnd = NULL 
   ); 
   CDHtmlDialog( 
   UINT nIDTemplate, 
   UINT nHtmlResID = 0, 
   CWnd *pParentWnd = NULL 
   ); 

   你可以看到和CDialog不同的就在於第二個引數,表示在對話方塊建立時是否自動載入HTML,這裡必須說明的是HTML必須以資源的形式存放,這個引數指明的是資源的ID或名稱。

   或者你可以利用 

   BOOL LoadFromResource( 
   LPCTSTR lpszResource 
   ); 
   BOOL LoadFromResource( 
   UINT nRes 
   ); 
   將HTML內容在後期進行裝載。

  頁面瀏覽 

   此外一些函式如:OnNavigateComplete,OnBeforeNavigate,Navigate等用於頁面轉換的函式,在以前的CHtmlView中就有這裡就不再作講解。 

得到當前URL 

   void GetCurrentUrl( 
   CString& szUrl 
   ); 

得到網頁中的DHTML元素的指定介面 

   HRESULT GetElementInterface( 
   LPCTSTR szElementId, 
   REFIID riid, 
   void** ppvObj 
   ); 

   第一個引數指定,第二個引數指定介面ID,第三個引數返回介面指標。 

得到網頁中的DHTML元素的IHTMLElement介面 

   HRESULT GetElement( 
   LPCTSTR szElementId, 
   IHTMLElement **pphtmlElement 
   ); 
   相當於呼叫 GetElementInterface(szElementId,IHTMLElement,pphtmlElement); 

   這個函式非常的重要,因為如果要得到DHTML的內容就必須通過頁面上的各個元素的屬性來得到,例如:對於Input type=text的屬性value就是輸入的值,對於p的屬性innerText就是段落中的內容。 

   函式的第二個引數就是元素的名稱。 

   函式的第二個引數,是一個指向指標的指標,通過它得到IHTMLElement的介面。函式返回值是HRESULT其值的定義符合COM中對返回值的定義。(如果你不瞭解,可以簡單的檢測返回值是否等於S_OK) 

得到元素的innerText和innerHTML的屬性 

   innerHTML屬性: 
   BSTR GetElementHtml( 
   LPCTSTR szElementId 
   ); 
   innerText屬性: 
   BSTR GetElementText( 
   LPCTSTR szElementId 
   ); 
   相當於呼叫IHTMLElement介面的gett_innerHTML和get_innerText方法 

   與之對應的是設定元素的innerText和InnerHTML屬性: 
   innerHTML屬性: 
   void SetElementHtml( 
   LPCTSTR szElementId, 
   BSTR bstrText 
   ); 
   innerText屬性: 
   void SetElementText( 
   LPCTSTR szElementId, 
   BSTR bstrText 
   ); 
   相當於呼叫IHTMLElement介面的put_innerHTML和put_innerText方法 

示範程式碼 

   假設頁面上的程式碼為:<p id=p2>test</p>,執行下面程式碼可以顯示原來的內容和將新內容設定為:abcdefg 

   CComPtr<IHTMLElement> spP1; 
   HRESULT hr = S_OK; 

   // Use the template overload 
   hr = GetElementInterface("p2", &spP1); 
   // 或者 hr = GetElement("p2", &spP1); 
   // 或者 hr = GetElementInterface("p2", IID_IHTMLElement, reinterpret_cast<void**>(&spP1)); 
   if(S_OK == hr) 
   { 
   BSTR bStr; 
   spP1->get_innerHTML(&bStr); 
   CString szTemp; 
   szTemp = bStr; 
   AfxMessageBox(szTemp); 

   CString strTable="abcdefg"; 
   BSTR bstrTable = strTable.AllocSysString(); 
   spP1->put_innerHTML(bstrTable); 
   } 
   或者利用SetElementHtml和SetElementText來進行設定: 
   BSTR bStr; 
   bStr = GetElementHtml("p2"); 
   CString szTemp; 
   szTemp = bStr; 
   AfxMessageBox(szTemp); 
   CString strTable="ABCDEFG"; 
   BSTR bstrTable = strTable.AllocSysString(); 
   //spP1->put_innerHTML(bstrTable); 
   SetElementHtml("p2",bstrTable); 
事件處理對映巨集 

基本格式 

BEGIN_DHTML_EVENT_MAP(className ) 
   DHTML_EVENT_ONCLICK(elemName, memberFxn ) //處理onclick事件 
   DHTML_EVENT_ONFOCUS(elemName, memberFxn ) //處理onfocus事件 
   DHTML_EVENT_ONKEYDOWN(elemName, memberFxn ) //處理onkeydown事件 
   DHTML_EVENT_ONMOUSEMOVE(elemName, memberFxn ) //處理mousemove事件 
   DHTML_EVENT_ONMOUSEOUT(elemName, memberFxn ) //處理mousemoveout事件 
   等等……… 
   END_DHTML_EVENT_MAP() 

   更詳細的說明可以查閱MSDN中DHTML Event Map Macros部分。MSDN中對可以處理的事件進行了詳細的說明。DHTML中的事件與Windows中訊息不是同一個概念,雖然對映巨集的形式很相同。 

新增對映處理程式碼 

   我在VC7中沒有發現自動新增各種事件對映的方法,只能通過手工新增程式碼的方式。 

   定義事件處理函式: 
   函式原型為:HRESULT urClass::OnXXXXX(IHTMLElement* /*pElement*/) 
   新增訊息對映: 
   BEGIN_DHTML_EVENT_MAP(urClass) 
   DHTML_EVENT_ONCLICK(_T("id name"), OnXXXXX) 
   END_DHTML_EVENT_MAP() 

   下面是一段示範程式碼: 
   // mydlg.h 
   class CmydhtmlDlg : public CDHtmlDialog 
   { 
   // 構造 
   public: 
   CmydhtmlDlg(CWnd* pParent = NULL); // 標準建構函式 

   // 對話方塊資料 
   enum { IDD = IDD_MYDHTML_DIALOG, IDH = IDR_HTML_MYDHTML_DIALOG }; 

   protected: 
   virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支援 
   HRESULT OnButtonOK(IHTMLElement *pElement); 
   HRESULT OnButtonCancel(IHTMLElement *pElement); 
   HRESULT OnButtonTest1(IHTMLElement *pElement); 
   HRESULT OnButtonTest2(IHTMLElement *pElement); 
   HRESULT OnButtonTest3(IHTMLElement *pElement); 
   HRESULT OnSelectTest1(IHTMLElement *pElement); 
   HRESULT OnDivMouseMove1(IHTMLElement *pElement); 
   HRESULT OnDivMouseOut1(IHTMLElement *pElement); 

   //mydlg.cpp 
   BEGIN_DHTML_EVENT_MAP(CmydhtmlDlg) 
   DHTML_EVENT_ONCLICK(_T("ButtonOK"), OnButtonOK) 
   DHTML_EVENT_ONCLICK(_T("ButtonCancel"), OnButtonCancel) 
   DHTML_EVENT_ONCLICK(_T("Test1"), OnButtonTest1) 
   DHTML_EVENT_ONCLICK(_T("Test2"), OnButtonTest2) 
   DHTML_EVENT_ONCLICK(_T("Test3"), OnButtonTest3) 
   DHTML_EVENT_ONCHANGE(_T("s1"), OnSelectTest1) 
   DHTML_EVENT_ONMOUSEMOVE(_T("d1"), OnDivMouseMove1 ) 
   DHTML_EVENT_ONMOUSEOUT(_T("d1"), OnDivMouseOut1 ) 
   END_DHTML_EVENT_MAP() 

   HRESULT CmydhtmlDlg::OnButtonOK(IHTMLElement* /*pElement*/) 
   { 
   OnOK(); 
   return S_OK; 
   } 

   HRESULT CmydhtmlDlg::OnButtonCancel(IHTMLElement* /*pElement*/) 
   { 
   OnCancel(); 
   return S_OK; 
   } 

   HRESULT CmydhtmlDlg::OnButtonTest1(IHTMLElement* /*pElement*/) 
   { 
   AfxMessageBox("test1 button clicked"); 
   return S_OK; 
   } 

   HRESULT CmydhtmlDlg::OnSelectTest1(IHTMLElement* /*pElement*/) 
   { 
   TRACE("select1 changed\n"); 
   return S_OK; 
   } 

   HRESULT CmydhtmlDlg::OnDivMouseMove1(IHTMLElement* /*pElement*/) 
   { 
   TRACE("div1 mouse move\n"); 
   return S_OK; 
   } 

   HRESULT CmydhtmlDlg::OnDivMouseOut1(IHTMLElement* /*pElement*/) 
   { 
   TRACE("div1 mouse out\n"); 
   return S_OK; 
   } 

各種DDX幫助巨集 

DDX巨集介紹 

如同CDialog類一樣,CHtmlDialog也提供各種DDX幫助巨集來與HTML頁面上的控制元件交換資料。

  遺憾的是VS7中無法為CDHTMLDialog 的子類自動新增DDX變數,必須通過手工新增。

   設定innerText和innerHTML屬性 

   DDX_DHtml_ElementInnerText( 
   CDataExchange* dx, 
   LPCTSTR name, 
   CString& var 
   ) 
   和 
    DDX_DHtml_ElementInnerHtml( 
   CDataExchange* dx, 
   LPCTSTR name, 
   CString& var 
   ) 
   相當與前面提到的設定和獲取innerText,innerHTML屬性。 

   獲取和設定控制元件中的值

  在DHTML中利用“物件名程.value”可以得到控制元件中輸入的值,利用DDX也同樣可以得到。 

   DDX_DHtml_ElementValue( 
   CDataExchange* dx, 
   LPCTSTR name, 
   var 
   ) 
   用於在控制元件和物件之間交換資料。 

   使用方法

  假設HTML檔案中程式碼如下 

   <p id="p4"><b>p4 for ddx</b></p> 
   <input type="text" ID="input1" size="20" value="input1 for ddx" NAME="input1"> 
   <input type="text" ID="input2" size="20" value="101" NAME="input2"> 

   在H檔案中新增變數定義: 
   public: //DDX 
   CString m_szP4,m_szInput1; 
   int m_iInput2; 

   在類的建構函式中賦初值: 
   CmydhtmlDlg::CmydhtmlDlg(CWnd* pParent /*=NULL*/) 
   : CDHtmlDialog(CmydhtmlDlg::IDD, CmydhtmlDlg::IDH, pParent) 
   { 
   m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); 
   m_szP4 = "test for p4"; 
   m_szInput1= "test for input1"; 
   m_iInput2 = 101; 
   } 

   在CPP檔案中的void CmydhtmlDlg::DoDataExchange(CDataExchange* pDX)函式中新增程式碼: 
   void CmydhtmlDlg::DoDataExchange(CDataExchange* pDX) 
   { 
   CDHtmlDialog::DoDataExchange(pDX); 
   //// for html ddx 
   DDX_DHtml_ElementInnerHtml(pDX,"p4",m_szP4); //對應 p4 
   DDX_DHtml_ElementValue(pDX,"input1",m_szInput1); //對應 input1 
   DDX_DHtml_ElementValue(pDX,"input2",m_iInput2); //對應 input2 
   } 
   使用是與CDialog一樣利用UpdateData。 
   HRESULT CmydhtmlDlg::OnButtonTest4(IHTMLElement* /*pElement*/) 
   { 
   UpdateData(); 
   TRACE("p4=%s\n",m_szP4); 
   CString szTemp=m_szP4; 
   m_szP4 =m_szInput1; 
   m_szInput1=szTemp; //對換p4和input1中內容 
   m_iInput2 ++; //將input2中數字加一 
   UpdateData(FALSE); 
   return S_OK; 
   } 

一個簡單的例子 

   最後介紹一下如何利用VC7建立一個利用CDHtmlDialog的工程。

  首先建立工程,進行如下設定: 


   在資源管理中修改HTML檔案: 


   最後新增自己的程式碼。我提供的例子中所使用的函式在上面都已經提到。