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)
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檔案:
最後新增自己的程式碼。我提供的例子中所使用的函式在上面都已經提到。