View与Frame的分离
2010-07-01 20:43:12 来源:WEB开发网一般来说,你可以使用res://modulename访问任何存储在EXE和DLL里的资源。res:是一个类似http:,ftp:,file:,或mailto:的协议。它告诉浏览器资源的路径和名字,细节工作浏览器知道如何去做!:) 为实现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有点迷惑。还记得我们刚开始谈到的CStatic吗? 我们打算用它来代表CHtmlCtrl控件,它将从CStatic建立一个CHtmlCtrl控件对象,这是一个子类化的过程,该对象将和CStatic有同样的ID,大小和位置。这么做很方便,很有效!:)
BOOL CHtmlCtrl::CreateFromStatic(UINT nID, CWnd* pParent)
{
CStatic wndStatic;
if (!wndStatic.SubclassDlgItem(nID, pParent))
return FALSE;
// Get static control rect
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
}
然后是使用CHtmlCtrl::LoadFromResource打开页面,它从CHtmlView继承而来。当然偶也可以这样打开页面:res://AboutHtml.exe/about.html OK! 偶已经向你展示了CHtmlCtrl如何通过回避CView而顺利代替frame在dialog里显示!。偶也介绍了如何如何在资源文件里定位HTML文件和图象文件。并且告诉你如何打开一个Web页面。但还有一个极为精彩的处理没有告诉你!:) ,能猜到是什么吗? 哇哈哈哈!!! 看到About对话框里的OK按钮了吧? 它并不是一个按钮!!仅仅是HTML文件里的一副图片! 偶使用了Javascript使得它在被单击时有up和down两种状态,但是它是如何和我们的对话框程序通讯的呢??? 你说好玩不?
如果你搞过DHTML,你可能会想到DHTML文档层可使用COM发现IMG元素然后监听它的OnClick事件。但是那样做对于偶这样的COM半文盲是way,way,way,WAY痛苦和麻烦的工作!!:( 其实,有一个更为简单的方法。假设你让这个"button"链接到一个叫做ok的文档: 现在,当用户单击它,浏览器将转到ok文件。但在它这么做以前,控制权交给 CHtmlCtrl::OnBeforeNavigate2。这时CHtmlCtrl可以做任何合法的事情:
<A href="ok"><IMG …></A>
void CmyHtmlCtrl::OnBeforeNavigate2(
LPCTSTR lpszURL,…,BOOL *pbCancel)
{
if(_tcscmp(lpszURL,_T("ok"))==0)
{
//"ok" clicked
*pbCancle=TRUE; // abort
// will close dialog
GetParent()->SendMessage(WM_COMMAND,IDOK);
}
}
[这是多么振奋人心的消息?? 想一想,我们几乎可以让对话框做几乎所有能做的事情! 而且我们可以将Web页面处理的更为美观!!:]] 所以,ok并不正真的是另一个文件,而CHtmlCtrl正是利用它来解释OK按钮!! 太完美了! 为了让这个想法更紧凑,偶引入了一个伪协议! 叫做:app:。用它来代替使用ok,在about.htm里正真的链接是app:ok。当CHtmlCtrl发现浏览器试图导航到app:somewhere时,它调用一个新的虚函数,CHtmlCtrl::OnAppCmd,它用somewhere作为参数,并cancels调航(navigation),所以CmyHtmlCtrl并没有重载OnNavigate2,而是重载了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"。好了!! 可以做你自己想做的事去了!…在你疯狂的code之前,提醒几句:加载IE DLLs需要极少的等待,但是如果加载About对话框超过10秒并且搬出来个沙漏晃来晃去,用户将感到非常不舒服!:)。最后,当你在About对话框里单击鼠标右键,会弹出个标准的浏览器快捷菜单,你可能觉得这是多余的,或者出于保护你的源代码的目的,你会买力的屏蔽调右键的功能。其实这很简单,你仅仅需要在HTML的 标签里加入一句脚本代码……但我们毕竟是在玩VC。所以,尽管麻烦,我们还是很乐意尝试。这个也不难!! 我们同样使用子类化的原理就能实现。但不是现在,而是将来的某个时候!! :)
本文配套源码
更多精彩
赞助商链接