mfcmfc 界面库问题

int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
lpCmdLine,
TCHAR pszFileName[256] = _T(&&);
UINT uRet = SaveDialog(lpCmdLine);
return TRUE;
UINT SaveDialog(TCHAR* pszFilePath)
BOOL bRet = FALSE;
OPENFILENAME
TCHAR szBuff[256];
BOOL bEnSystem = FALSE;
TCHAR szExt[MAX_PATH];
int nLen = 0;
memset(szExt, 0, MAX_PATH);
lstrcpy(szExt,
_T(&PQ文档(*.PQ)&));
nLen = lstrlen(_T(&PQ文档(*.PQ)&));
lstrcpy(&szExt[nLen+1], _T(&*.PQ&));
int cbPath = MAX_PATH;
if (pszFilePath == NULL || cbPath &= 0)
return FALSE;
if (lstrlen(pszFilePath) & cbPath)
pszFilePath[0] = 0;
memset(&ofn,0,sizeof(OPENFILENAME));
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hInstance = hI
ofn.hwndOwner = NULL;
ofn.lpstrFilter = szE
ofn.lpstrCustomFilter = NULL;
ofn.lpstrFile = pszFileP
ofn.nMaxFile = cbP
if (bEnSystem)
ofn.lpstrTitle = _T(&Input save filename&);
ofn.lpstrTitle = _T(&输入保存文件名&);
ofn.Flags = OFN_EXPLORER|OFN_NOREADONLYRETURN|OFN_NONETWORKBUTTON;//|OFN_ENABLETEMPLATEHANDLE;//|OFN_ENABLEHOOK| OFN_ENABLETEMPLATE|
bRet = GetSaveFileName(&ofn);
if (str.find(_T(&.PQ&))==-1)
lstrcat(pszFilePath, _T(&.PQ&));
pszFilePath[0] = 0;
------解决方案--------------------
可以试试ofn.hwndOwner = ::GetDesktopWindow();
------解决方案--------------------SetWindowPos TOPMOST
12345678910
12345678910
12345678910 上一篇:下一篇:文章评论相关解决方案 12345678910 Copyright & &&版权所有MFC窗口坐标问题
MFC窗口坐标问题
BOOL CmfcdialogtestDlg::OnInitDialog()
/*.............其它代码.............*/
/*****************for testing***************/
CRect wndRect1;
CRect wndRect2;
/****首先看对话框的******/
this-&GetWindowRect(&wndRect1); //PrintRect("Dialog:GetWindowRect", wndRectScreen1);
this-&ScreenToClient(&wndRect1); //PrintRect("Dialog:ScreenToClient", wndRectClient1);
this-&GetClientRect(&wndRect2); //PrintRect("Dialog:GetClientRect", wndRectClient2);
this-&ClientToScreen(&wndRect2); //PrintRect("Dialog:ClientToScreen", wndRectScreen2);
/****再看控件的**********/
CRect ctrlRect1;
CRect ctrlRect2;
CStatic *pCtrl = (CStatic*)GetDlgItem(IDC_STC_TEST);
pCtrl-&GetClientRect(&ctrlRect1); //PrintRect("static:GetClientRect", ctrlRectClient1);
pCtrl-&ClientToScreen(&ctrlRect1); //PrintRect("static:ClientToScreen", ctrlRectScreen1);
pCtrl-&GetWindowRect(&ctrlRect2); //PrintRect("static:GetWindowRect", ctrlRectScreen2);
pCtrl-&ScreenToClient(&ctrlRect2); //PrintRect("static:ScreenToClient", ctrlRectClient2);
/*****************ending********************/
/*.............其它代码.............*/
GetWindowRect: +
0x {top=0 bottom=378 left=0 right=566}
ScreenToClient:+
0x {top=-25 bottom=353 left=-3 right=563}
GetClientRect: +
0x {top=0 bottom=350 left=0 right=560}
ClientToScreen:+
0x {top=25 bottom=375 left=3 right=563}
CRect *控件:
GetClientRect:
&ctrlRect1
0x {top=0 bottom=170 left=0 right=285}
ClientToScreen:  +
&ctrlRect1
0x {top=127 bottom=297 left=73 right=358}
GetWindowRect:
&ctrlRect2
0x {top=127 bottom=297 left=73 right=358}
ScreenToClient:  +
&ctrlRect2
0x {top=0 bottom=170 left=0 right=285}
发表评论:
TA的最新馆藏[转]&[转]&& VS2010/MFC编程入门之四十一(文档、视图和框架:分割窗口)
VS2010/MFC编程入门之四十一(文档、视图和框架:分割窗口)
&&&&& 上一节中鸡啄米讲了,本节主要讲讲在中如何分割窗口。&&&&& 分割窗口概述&&&&&&分割窗口,顾名思义,就是将一个窗口分割成多个窗格,在每个窗格中都包含有视图,或者是同一类型的视图,或者是不同类型的视图。& &&&& MFC分割窗口的方式有两种,动态分割和静态分割。&&&&&& 动态分割窗口通常用于创建同一个文档对应的多个视图,而且这些视图一般都是同一类型的视图,能够在用户编辑文档的不同部分时提供方便。&&&&&& 大家看下Word里的动态分割窗口就很明白了,以Word 2007文档为例,在菜单中点击&视图&-&&拆分&,就可以看到一条随鼠标移动的分隔条,当我们在文档中某个位置按下鼠标左键时,分割条就固定了下来,生成了上下两个分割窗格,通过滚动每个窗格中的垂直滚动条可以看到,两个窗格中的内容相同,这就是所说的对应同一个文档的同一类视图。&&&&&& 动态分割窗口最多可以有两行两列。&&&&&& 静态分割窗口比较常见。我们经常能看到某个软件打开后,界面窗口默认被分割成了几个窗格,这就是静态分割窗口。&& &&& 静态分割窗口指在窗口创建时,分割的窗格就已经生成了,而且用户不能改变窗格的数量和顺序。静态分割窗口最多支持16行16列。通常静态分割窗口的每个窗格中包含不同类的视图,当然也可以是同一类的视图。&&&&&& CSplitterWnd类&&& && MFC中的分割窗口类-CSplitterWnd类提供了分割窗口的功能。CSplitterWnd类中包含一个分割器窗口,该分割器窗口就是一个包含多个窗格的窗口。我们分割窗口时就是直接在此分割器窗口中分割的。&& &&& 鸡啄米下面介绍三个最常用的成员函数:
virtual&BOOL&Create( &&
&&&CWnd*&pParentWnd, &&
&&&int&nMaxRows, &&
&&&int&nMaxCols, &&
&&&SIZE&sizeMin, &&
&&&CCreateContext*&pContext, &&
&&&DWORD&dwStyle&=&WS_CHILD&|&WS_VISIBLE&|&WS_HSCROLL&|&WS_VSCROLL&|&SPLS_DYNAMIC_SPLIT, &&
&&&UINT&nID&=&AFX_IDW_PANE_FIRST& &&
);&&&&&&&& 创建动态分割窗口。参数pParentWnd为分割器窗口的父框架窗口;参数nMaxRows为分割器窗口的最大行数,不能超过2;参数nMaxCols为分割器窗口的最大列数,也不能超过2;参数sizeMin为窗格能显示的最小尺寸,如果窗格尺寸小于sizeMin则不显示;参数pContext为指向CCreateContext结构的指针,大多数情况下可以赋值为父框架窗口的pContext;参数dwStyle指定窗口风格;参数nID为分割窗口的ID,除非分割器窗口嵌入到另一个分割器窗口中,否则可以取值AFX_IDW_PANE_FIRST。
virtual&BOOL&CreateStatic( &&
&&&CWnd*&pParentWnd, &&
&&&int&nRows, &&
&&&int&nCols, &&
&&&DWORD&dwStyle&=&WS_CHILD&|&WS_VISIBLE, &&
&&&UINT&nID&=&AFX_IDW_PANE_FIRST& &&
);&&&&& && 创建静态分割窗口。参数pParentWnd、dwStyle和nID同上;参数nRows为行数,不能超过16;参数nCols为列数,同样不能超过16。
virtual&BOOL&CreateView( &&
&&&int&row, &&
&&&int&col, &&
&&&CRuntimeClass*&pViewClass, &&
&&&SIZE&sizeInit, &&
&&&CCreateContext*&pContext& &&
);&&&&&&&& 为静态分割窗口创建窗格视图。参数row指定分割器窗口中放置新视图的行;参数col指定放置新视图的列;参数pViewClass指定新视图的CRuntimeClass对象;参数sizeInit指定新视图的初始大小;参数pContext为指向CCreateContext结构的指针,通常可以赋值为传递给父框架窗口的重载函数CFrameWnd::OnCreateClient的pContext参数值。&&&&&& 动态分割窗口&&&&&& 创建动态分割窗口的步骤为:&& &&& 1. 在父框架类中定义一个CSplitterWnd类型的成员对象。&& &&& 2. 重载父框架类的CFrameWnd::OnCreateClient成员函数。&& &&& 3. 在重载的CFrameWnd::OnCreateClient函数中调用CSplitterWnd成员对象的Create函数。&& &&& 下面鸡啄米给大家一个实例。同样以中创建Example34工程为例,我们要实现在主框架窗口的客户区中创建两行两列的动态分割窗口。以下是创建动态分割窗口的具体步骤:&& &&& 1. 在MainFrm.h文件中为CMainFrame类添加成员对象:CSplitterWnd m_wndS。&&& && 2. 在Class View类视图中找到CMainFrame类,右键点击,在右键菜单中选择Properties,就会显示属性页,然后在属性页的工具栏上点击Tip为Overrides的按钮,下面的列表中就列出了能够重载的函数,找到OnCreateClient生成重载函数。&& &&& 3. 在MainFrm.cpp文件中找到刚重载的OnCreateClient函数修改如下:
BOOL&CMainFrame::OnCreateClient(LPCREATESTRUCT&lpcs,&CCreateContext*&pContext) &&
&return&m_wndSplitter.Create(this,2,&2,&CSize(10,&10),&pContext); &&
}&&&&&&&& 4. 在Resource View资源视图中,打开Menu下的IDR_MAINFRAME菜单,在View下添加一个菜单项,Caption设为Splitter Window,ID设为(一定要设为)ID_WINDOW_SPLIT。这样在运行结果界面中点击此菜单项时MFC会执行一些操作显示动态分割窗口。&& &&& 5. 运行程序,点击菜单中的View-&Splitter Window菜单项,创建动态分割窗口后效果如下:&&&&&&& 静态分割窗口&& &&& 创建静态分割窗口的步骤为:&& &&& 1. 在父框架类中定义一个CSplitterWnd类型的成员对象。&& &&& 2. 重载父框架类的CFrameWnd::OnCreateClient成员函数。&& &&& 3. 在重载的CFrameWnd::OnCreateClient函数中调用CSplitterWnd成员对象的CreateStatic成员函数,然后可以调用CSplitterWnd成员对象的CreateView成员函数为每个窗格创建视图。&&& &&& 鸡啄米仍通过Example34工程给大家一个实例,目的是在主框架窗口中的客户区创建一个两行一列的静态分割窗口。如果已经试验过动态分割窗口的创建,那么麻烦撤销那些修改吧。创建静态分割窗口的具体步骤如下:&& &&& 1. 在MainFrm.h文件中为CMainFrame类添加成员对象:CSplitterWnd m_wndS。&& &&& 2. 在Class View类视图中找到CMainFrame类,右键点击,在右键菜单中选择Properties,就会显示属性页,然后在属性页的工具栏上点击Tip为Overrides的按钮,下面的列表中就列出了能够重载的函数,找到OnCreateClient生成重载函数。&& &&& 3. 在MainFrm.cpp文件中找到刚重载的OnCreateClient函数进行修改。因为鸡啄米没有新建其他视图类,所以上下两个窗格的视图都是CExample34View。为了能识别CExample34View类,还需在MainFrm.cpp文件中添加#include &Example34View.h&,在Example34View.h文件中添加#include &Example34Doc.h&。最终OnCreateClient函数修改如下:
BOOL&CMainFrame::OnCreateClient(LPCREATESTRUCT&lpcs,&CCreateContext*&pContext) &&
&&&&CRect& &&
&&&&GetClientRect(&rc); &&
&&&&if&(!m_wndSplitter.CreateStatic(this,&2,&1)) &&
&&&&&&&&return&FALSE; &&
&&&&if&(!m_wndSplitter.CreateView(0,&0,&RUNTIME_CLASS(CExample34View),&CSize(rc.Width(),&rc.Height()/2),&pContext)) &&
&&&&&&&&return&FALSE; &&
&&&&if&(!m_wndSplitter.CreateView(1,&0,&RUNTIME_CLASS(CExample34View),&CSize(rc.Width(),&rc.Height()/2),&pContext)) &&
&&&&&&&&return&FALSE; &&
&&&&return&TRUE; &&
}&&&&&&&& 4. 运行程序,在结果界面中关掉其他面板后效果如下:&&& &&& 如果大家想创建在其中某个窗格中再嵌套分割窗口,那么就需要再定义一个CSplitterWnd对象,以父窗格所在的CSplitterWnd对象为父框架窗口创建分割窗口即可。&& &&& 分割窗口的内容就讲到这里了。鸡啄米依然谢谢大家的支持。
除非特别注明,文章均为原创
转载请标明本文地址:
作者:鸡啄米
&&( 20:57:7)&&( 21:46:22)&&( 22:23:20)&&( 20:55:23)&&( 21:27:35)&&( 23:13:50)&&( 21:53:4)&&( 22:4:25)&&( 21:43:59)&&( 0:11:32)
来学习学习了,谢谢分享鸡啄米 于
23:57:42 回复常来看看啊
5年起我学过.net,现在都已经好无印象了,对于vs更加是陌生,时间这真的很快过。鸡啄米 于
23:19:09 回复有其他出路也很好啊,呵呵
太难了,没坚持。
学习学习,支持一下
原来可以这么写啊
net,是什么意思?咱是新手不懂这些专业术语,能解释一下吗?
楼主,你的实力第二步的在classview类视图内找到CMAINFRAME是什么意思?怎么 找不到?看不懂你这句话啊!鸡啄米 于
23:38:46 回复classview类视图中有一项是CMainFrame类啊。首先要切换到类视图。
文档、视图和框架,生成完了,用来作什么呢.
您好,我在静态分割窗口实例中最后出现编译错误,错误的来源是“Example34View.h”中的1&c:\users\cpt-yx\documents\visual studio 2010\projects\example34\example34view.h(16): error C2143: syntax error : missing ';' before '*'请问这是什么原因呢?谢谢topsun 于
10:10:39 回复在出错的.h中的开头增加#include &XXXXXXXXDoc.h&因为你的CXXXXXXDoc没有声明。
楼主您好:您写的很好,只是我发现一个小问题您没说:就是动态创建的时候,添加了菜单,之后,您没有说为什么点击菜单可以实现动态创建。这个关键在创建的ID上,因为这个ID:ID_WINDOW_SPLIT 在String Table里已经定义了。这个ID就是响应动态创建拆分窗口的。还是说一下比较好,不然新手看到这里可能会懵的,因为这个菜单没有相应COMMAND消息。呵呵。我想如果用别的ID,可以相应COMMAND消息,调用OnCreateClient函数也可以吧?有兴趣的朋友可以试试。但是这里的最大问题就是OnCreateClient函数的参数。不会了。有高手可以讲讲。谢谢
楼主您好!我在写静态嵌套窗口分割的时候碰到了点问题,实在不知道怎么解决,求助。就是在嵌套分割的时候,先分成两行一列,然后对把第一行再分成两列。分割完之后发现上面两个视图的高度无法修改,始终是0。如果是先分成两行一列,把第二行再分成两列,分割完之后可以调整第一行的高度,下面两列的高度不为0。再如果是先分成3行一列,再分割第一行或者第二行的时候高度也是0,不知道怎么修改...求高手赐教...谢谢
经过近一个月的加班,终于要看完了。在看完最后一节的时侯,先感谢博主无私的分享精神,同时对博主严谨的治学态度表示崇高的敬意!我感觉博主的《VS2010/MFC编程入门教程》有以下三个特点:一是整体结构合理,层次分明;二是讲解深入浅出,明了易学;三是实例简单易懂,适合入门。再次感谢楼主,评论中有不妥之处谅解!
你好,我想请问用mfc如何创建多窗口,就是点击一个按键后弹出另一个界面。希望指教一下。谢谢。
完全随机文章关于mfc界面美化问题?
用MFC做了一个小程序,觉的界面不太好看,请问有什么办法可以美化一下界面的?具体该怎么做?
09-10-12 &
方案一、皮肤,网上有很多现成的皮肤加载方案,例如SkinMagic等,也有开源的,最简单。方案二、基于对话框的使用CDialogSK和CButtonST简单美化(即贴图)。方案三、使用Flash做界面。方案四、使用网页做界面,例如“添加/删除程序”。方案五、使用WPF
请登录后再发表评论!下次自动登录
现在的位置:
& 综合 & 正文
MFC界面–利用CHtmlView和HTML制作新风格的界面(包括CView和Dialog)
一、文档视图形式,以一个视图cview(chtmlview)作为首页界面
用过 Outlook Express 的很多人都对其第一页的 HTML 界面感到新奇,很明显这是使用 DHTML 技术,加入了一些 Java Script 的一个网页,但它能够和应用进行交互操作。其实利用 VC6.0 的新加入的 MFC 类 CHtmlView ,你也可以实现这样一个令人激动的程序界面。这个界面可以利用 HTML ,这是很有意义的,想象一下,你在 HTML 中实现的效果,全部可以放在程序的界面中,而你所做的只是写了一个 HTML 文件和少量的编程。
   CHtmlView 是 MFC 新加入的一个类,如果你看一下 MFC 关于这个类的,就会发现在其内部封装了接口 IWebBrowser2 。这个接口实际上是 IE 的接口。也就是说,你可以通过这个类来调用强大的 IE 来显示 HTML 页面,每个人都可以利用这个类,轻松的写出一个浏览器。 VC 中也带了一个使用这个类写的浏览器的例子 MFCIE ,可以参考。
   利用 CHtmlView 显示页面是很简单的。你只要在资源中加入 HTML 页面资源,程序中加入下面一句语句就可以实现。
   LoadFromResource(ID_XXX);//ID_XXX 是资源的定义
   解决这个问题的核心是如何利用 CHtmlView 把用户对 HTML 页面的操作传送给应用程序。这里看似很神秘,但实际上有一个技巧,可以截获用户的输入。在类 CHtmlView 中有一个事件 OnBeforeNavigate2 ,当浏览器被重新导向之前,会激活这个事件。比如说每当用户按下了 HTML 中的超级链接,或者用户在地址栏输入新的地址,还有程序员调用接口的 Navigate 方法,浏览器要转向新地址的时候,都会激活这个事件。而在这里,当你实现 HTML 界面的时候,用户通过点击页面上的链接来激活命令,所以我们可以在这个事件里做一些处理,这个事件的参数中有两个比较重要,
lpszURL 就是在 HTML 页面中 href 指定的地址,你可以给各个链接设置相应的地址,通过这个参数的内容就可以识别用户点击的链接。而 pbCancel 可以指定是否取消导向,只要写入 *pbCancel = TRUE ,导向就被取消,不会发生了, CHtmlView 显示的还是现在的页面。让我们来看一下我写的例子程序 HtmlGUI 。
void CHtmlGUIView::OnBeforeNavigate2(LPCTSTR lpszURL, DWORD nFlags, LPCTSTR lpszTargetFrameName, CByteArray& baPostedData, LPCTSTR lpszHeaders, BOOL* pbCancel)
// TODO: Add your specialized code here and/or call the base class
if (ProcessCommand(lpszURL))
//URL was processed by the programmer defined code.
//cancel navigation
*pbCancel = TRUE;
CHtmlView::OnBeforeNavigate2(lpszURL, nFlags, lpszTargetFrameName, baPostedData, lpszHeaders, pbCancel);
BOOL CHtmlGUIView::ProcessCommand(LPCTSTR lpszURL)
if ( _tcscmp(lpszURL, _T("app:link1")) == 0 )
AfxMessageBox("Link1 was pressed, you can process your command here!");
return TRUE;
if ( _tcscmp(lpszURL, _T("app:link2")) == 0 )
AfxMessageBox("Link2 was pressed, you can process your command here!");
return TRUE;
//NOT processed by me.
if ( _tcscmp(lpszURL, _T("app:about")) == 0 )
::SendMessage(AfxGetMainWnd()-&GetSafeHwnd(), WM_MAINAPP_ABOUT,0,0);
return TRUE;
return FALSE;
   这里面我写了一个函数 BOOL CHtmlGUIView::ProcessCommand(LPCTSTR lpszURL) 来处理命令的映射,如果被导向的地址应该映射到程序的命令,则作相应的处理,并返回 TRUE ,表示已经被处理了,取消导向。否则返回 FALSE ,则调用 MFC 父类的函数,进行正常的操作。
   为了不露出破绽,最好屏蔽掉鼠标右键,所以还应该重载 PreTranslateMessage ,并加入如下。
BOOL CHtmlGUIView::PreTranslateMessage(MSG* pMsg)
// TODO: Add your specialized code here and/or call the base class
// Do not let View get Right button Message.
if ((pMsg-&message == WM_RBUTTONDOWN) ||
(pMsg-&message == WM_RBUTTONDBLCLK))
return TRUE;
return CHtmlView::PreTranslateMessage(pMsg);
   当用户按下右键或者双击右键的时候,返回 TRUE ,这样 CHtmlView 窗口就不会得到这两条消息了。当然你也可以利用页面中的 Script 来实现这个功能。
   另外在写 HTML 页面时有一些东西要注意。微软为了使资源中的 HTML 文件能够得到访问,为 IE 定义了一个可以称为 res 协议的东西。你可以在 IE 的地址栏中输入 res://x:\xxx\htmlgui.exe/gui.htm ( x:\xxx\ 为路径), IE 中应该显示出我的程序的 HTML 文件。其实当你用 IE 访问页面出错的的时候, IE 显示的出错信息也是放在 C:\WINDOWS\SYSTEM\SHDOCLC.DLL 中的。 HTML 中用到的图片,声音等等,显然也要放入程序资源中才比较好。所以这些东西要全部当作
HTML 加入到资源中。而且,最好直接使用文件名用作资源 ID ,在资源文件中按下面格式加入定义。
GUI.HTM HTML DISCARDABLE "res\\gui.htm"
PIC1.JPG HTML DISCARDABLE "res\\pic1.jpg"
WRITE.GIF HTML DISCARDABLE "res\\write.gif"
CHIMES.WAV HTML DISCARDABLE "res\\Chimes.wav"
【注意,提前把相应的htm和gif、jpg、wav等文件拷贝到工程的res文件夹下,然后在资源文件(以代码形式打开查看)中写入上述语句即可。】
   虽然 VC 的资源编辑器会把他们当本来显示,但是不要担心。只要你不要按文本去编辑他们就行了, CHtmlView 在加载页面的时候会正确显示他们的。不过千万不要把他们当作自定义或其他资源来加入,如果你那样做了, CHtmlView 加载时反而会不认识他们。为了确保 HTML 被正确显示,所有的图片和声音能被找到,所以在 HTML 文件中加入下面一行。
   & BASE url="res://HtmlGUI.exe/GUI.HTM"&
   CHtmlView 还有一个函数 CHtmlView::GetHtmlDocument 可以得到 Ative Document 对象的 IDispatch 接口,然后你应该可以利用这个接口 QueryInterface 出其他的接口,利用这些接口你可以在程序中动态地控制 HTML 页面的内容。如果有兴趣,好好看看 MSDN 联机帮助,研究一下吧。
   HTML 界面是一种快速,方便,效果独特,容易排错的全新的界面技术,而由于微软封装了 OLE 接口 IWebBrowser2 ,使它的实现的技术细节变得这么简单,让我们来创造更新更酷的界面吧,祝编程愉快!
【补充:HTMLVIEW中打开网页,填表提交后 出现脚本错误提示 “当前的网页脚本发生错误”请问如何不让这种提示出现】
第一个方案
SetSilent(TRUE);
如果第一个方案不行
上这段代码
C/C++ code
void CSimOOView::OnNavigateComplete2(LPCTSTR strURL)
CComPtr&IDispatch&
GetHtmlDocument();
CComPtr&IHTMLDocument2&
spDisp-&QueryInterface(IID_IHTMLDocument2, reinterpret_cast&void**&(&doc));
if(doc != NULL)
IHTMLWindow2 * pIhtmlwindow2 = NULL;
doc-&get_parentWindow(&pIhtmlwindow2);
if(pIhtmlwindow2 != NULL)
CString strJavaScriptCode = "function fnOnError(msg,url,lineno){}window.onerror=fnOnE";
BSTR bstrScript = strJavaScriptCode.AllocSysString();
CString strLanguage("JavaScript");
BSTR bstrLanguage = strLanguage.AllocSysString();
long lTime = 1 * 1000;
long lTimeID = 0;
VARIANT varL
varLanguage.vt = VT_BSTR;
varLanguage.bstrVal = bstrL
VARIANT pR
pIhtmlwindow2-&execScript(bstrScript, bstrLanguage, &pRet);
::SysFreeString(bstrScript);
::SysFreeString(bstrLanguage);
pIhtmlwindow2-&Release();
CHtmlView::OnNavigateComplete2(strURL);
具体使用时,在具体CView::OnInitialUpdate()函数中添加如下代码,有三种形式,任选一种即可
法1:Navigate2(_T("); //此法是直接打开远程网页
法2:this-&LoadFromResource(_T("firstpage.htm")); //此法是打开存放在exe中的二进制文件firstpage.hm。
法3:Navigate2(_T("WebPage\\FirstPage.htm"),NULL,NULL); //此法可以打开存放在工作目录下的WebPage目录中的FirstPage.htm文件,而且htm文件不必是二进制文件,甚至htm里面使用的图片等都可以不必是二进制文件,就像正常网页编辑那样使用,最重要的是法2不能使用外嵌的js文件,而法3想正常网页那样编辑然后嵌入到view中,没有法2那样的限制。
二、对话框形式,使用自定义的chtmlctrl控件
(1)转化htmlview为htmlctrl
Wow!! 几篇让人拍案的,啃完之后大呼过瘾!想不到微软也有如此精通windows编程的家伙?! 此时此刻,俺想到的是分享给KBASE里的兄弟们啊! 没的说,掌声伺候!!!!
罗头说了,最好不要把Frame/Doc/View拆的妻离子散。是啊,本来好好的一家人,谁会那么残忍呢!? 嘿嘿,偶只是给他们弄了个远房的亲戚。:)
Now, Stop 费话ing!! Let''s go on the stuff…
首先,这里有两个难点需要解决! 一是:既然最后的产物是CHtmlCtrl,如何能象其他控件(比如Button)随意的丢到对话框里呢? COM-&ActiveX?? 你说的,你自己做去吧!偶可是个COM稀里糊涂者!! 偶要比你想象地懒的多(鼓励程序员锻炼一下这种惰性! 好处多多)。 偶想,何不拉个替死鬼呢? 对了,CStatic不是可以随便被嗲来嗲去吗? 嗯,给它套上个SubclassDlgItem不就可以当成我们的CHtmlCtrl用了嘛! 有道理!! 然后是:View的确和Frame有着千丝万缕的联系。MFC是个半定制的框架,微软已做了很多手脚,说不定你在View里啪啪点几下,就有几个类似WM_MICROSPACE这样的消息传到了Frame里。然而控件是没有Frame可言的,而且控件也从不需要知道自己被放到了哪个容器里!!
所以,为了不至于编译器当啊当的乱叫,我们还要小心伺候着!:)
在继续往下做之前,你还要明确CHtmlView和我们最终生成的CHtmlCtrl到底有什么区别?
其实,区别仅仅是它们被使用的方法不同。控件通常是对话框里的子窗口---当然你可以把它作为任何窗口的子窗口。然而View却是专门为了实现MFC 文档视图结构而设计的。一个View有一个指向Document的指针并且被固定在一个特别的窗口里---人称:框架窗口(CFrameWnd)。对于Document来说,CView是它可以从形态上被表现的场作。但,指向Document的指针m_pDocument可能是NULL,所以每当我们在View里处理Document的时候,这么做是明智的:
1.If(m_pDocument!=NULL)
所以,View并不正真的需要一个Document,CHtmlView也不需要。你可能认为在CHtmlView里的Document就是一个HTML文件,但实际上,CHtmlView是使用IWebBrowser2实现的,而且它对MFC的文档视图结构一无所知。
那么需要一个Frame吗? 如果你仔细研究过相关的代码,就会发现:只是在极少地方,View知道自己属于一个Frame。大多数文档视图结构是在更高一级的类比如Frame本身和CDocTemplate里实现的,它们把Frame,View,Document紧紧的粘在了一起。View并不知道外面发生了什么,这样设计的文档视图系统有很多优点。理论上来说,View是被动地受Frame控制,而且没有其他途径,所以认为View知道它自己的父窗口是错误的。有两处CView( 也是CHtmlView的父类 )会假想自己在一个Frame里。第一处是CView::OnMouseActive,它是WM_MOUSEACTIVE消息的处理函数,当你在View里点击鼠标以后,它会做很多细致的工作。这些细致的工作是不重要的,但重要的是View调用了GetParentFrame以得到它的父窗口框架,然后CFrameWnd::GetActiveView激活当前的活动视图---所有的这一切,都建立在假设View是CFrameWnd的一个子窗口的基础之上。
另外一处是在CView::OnDestroy里:
1.voidCView::OnDestroy()
CframeWnd* pFrame = GetParentFrame();
If(pFrame!=NULL&&pFrame-&GetActiveView==this)
pFrame-&SetActiveView(NULL);
CWnd::OnDestroy();
在这里,View先让自己处于非活动状态。从另一个角度考虑,我们完全可以通过向父窗口发通知消息(Notification)代替C++方法调用从而回避掉View对Frame的依赖!! GetParentFrame可以返回一个CWnd,而非CFrameWnd,因为该函数只是强调了父窗口,而不是一定要返回一个特定的类。View可以通过发送一个类似WM_MICROSPACE的通知消息取代对CFrameWnd的方法调用,这些Notification会被"Frame"(或是CFrameWnd或是CfooWnd)正确的响应。
但是,无论如何,你必须清楚:当View被激活或进入非活动状态时,是Frame决定该如何响应,而不是View本身。任何系统都是如此;函数向下调用(从父到子),事件向上传递(从子到父)。一个子类从来都不会知道自己所在的容器!! 生活本身就不是完美的! 但幸运的是我们将会很容易的克服MFC给我们带来的难题! CHtmlCtrl类( here! )正是我们需要的:一个HTML "View" ,你可以在对话框或任何窗口里使用。CHtmlCtrl重载了OnMouseActive和OnDestroy从而回避CView那些给我们惹麻烦的代码。
01.intCHtmlCtrl::OnMouseActive(…)
returnCWnd::OnMouseActive(…);
06.voidCHtmlCtrl::OnDestroy()
CWnd::OnDestroy();
除此之外,CHtmlCtrl也重载了PostNcDestroy
1.voidCHtmlCtrl::PostNcDestroy()
CView正常的PostNcDestroy实现是使用delete this销毁View。对于Views来说,这是正常的处理方式,因为View是直接在堆里建立的。但是,控件一般是作为另一个窗口对象的成员存在的。这时你就不要delete了,它会被父对象delete掉。 通过以上的修改(OnMouseActive,OnDestroy和PostNcDestroy),CHtmlCtrl能顺利的在对话框里工作了!! 为此,偶写了个小程序:AboutHtml( 见源代码)显示一个About框(如图1)。那是完全用HTML写的。
HTML的资源:图片,音频文件(对了!甚至可以有声音)都被存储到EXE文件里。
2.ABOUT.HTML
HTML DISCARDABLE"res\\about.htm"
3.VCKBCOM.GIF HTML DISCARDABLE"res\\vckcom.gif"
4.OKUP.GIF
HTML DISCARDABLE"res\\okup.gif"
5.OKDN.GIF
HTML DISCARDABLE"res\\okdn.gif"
6.MOZART.WAV
HTML DISCARDABLE"res\\mozart.wav"
在一般的Web页面里,如果你这么做:& img src="vckcom.gif" / & 就需要把vckcom.gif放到当前目录下。对于访问一个存储在EXE文件里的资源,同样也要这样。这种情况下,你必须使用下面的代码帮助浏览器寻找你的HTML元素:
1.& BASE url=""&
浏览器就会知道当前的"目录"是res://AboutHtml.exe,所以当它遇到& img src="vckcom.gif" / &,它会自动找到res://AboutHtml.exe/vckcom.gif,否则,它将在HTML文件所在的当前目录下寻找。
一般来说,你可以使用res://modulename访问任何存储在EXE和DLL里的资源。res:是一个类似http:,ftp:,file:,或mailto:的协议。它告诉浏览器资源的路径和名字,细节工作浏览器知道如何去做!:) 为实现About对话框,偶写了个类,CAboutDialog,它有个CHtmlCtrl类型的成员m_page。我们来看看CaboutDialog的初始化过程:
1.BOOLCaboutDialog::OnInitDialog()
VERIFY(Cdialog::OnInitDialog());
VERIFY(m_page.CreateFromStatic(IDC_HTMLVIEW,this));
m_page.LoadFromResource(_T("about.htm"));
returnTRUE;
你可能对CHtmlCtrl::CreateFromStatic有点迷惑。 还记得我们刚开始谈到的CStatic吗? 我们打算用它来代表CHtmlCtrl控件,它将从CStatic建立一个CHtmlCtrl控件对象,这是一个子类化的过程,该对象将和CStatic有同样的ID,大小和位置。这么做很方便,很有效!:)
01.BOOLCHtmlCtrl::CreateFromStatic(UINTnID,
CWnd* pParent)
CStatic wndS
if(!wndStatic.SubclassDlgItem(nID, pParent))
returnFALSE;
wndStatic.GetWindowRect(&rc);
pParent-&ScreenToClient(&rc);
wndStatic.DestroyWindow();
returnCreate(NULL,
(WS_CHILD | WS_VISIBLE ),
然后是使用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可以做任何合法的事情:
1.& A href="ok"&& IMG … && /A &
01.voidCmyHtmlCtrl::OnBeforeNavigate2(
LPCTSTRlpszURL,…,BOOL
*pbCancel)
if(_tcscmp(lpszURL,_T("ok"))==0)
*pbCancle=TRUE;
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:
1.voidCmyHtmlCtrl::OnAppCmd(LPCTSTRlpszWhere)
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。所以,尽管麻烦,我们还是很乐意尝试。 这个也不难!! 我们同样使用子类化的原理就能实现。但不是现在,而是将来的某个时候!!
(2)交互深入
可以下载源码
在这之前补充我发现的一个问题:
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
【上面代码是CHtmlCtrl.cpp中的,但不能通过vs2008编译,原因是下面讲的是vc6环境下的。可能是vs2008使用的是atl3.0以上的版本的缘故。解决方法是把函数内部的东西都注释掉,只留下最后一句CWnd::OnDestroy();即可。不可只注释掉出错的m_pBrowserApp-&Release();这一句,否则表面没错,可能影响整个程序,导致崩溃。】
在以前的VC知识库 Online Journal 上有三篇文章:
“VC6中使用CHtmlView在对话框控制中显示HTML文件”(第六期)
“如何禁用HTML页面的上下文菜单”(第十一期)
“Convert CHtmlView to CHtmlCtrl...”(第十七期)
这三篇文章的原文实际上都出自 MSDN Magazine 及其前身 MSJ 的“C++ Q&A”专栏作家 Paul DiLascia 之手。此君从1995年开始就成为 MS 在 C++/MFC 方面的高级写手,Paul 在 Windows 应用开发领域的造诣颇深。直到现在仍然在为该专栏撰写技术文章,只不过其文章已不仅仅涉及 C++/MFC,偶尔也写一些 C#。为了微软的 .NET 战略,Paul 可谓忠实、勤奋和敬业......
本文是以上文章所涉及内容的延伸。如果你已经对前述文章讨论的东西了然于心,那么可以直接切入本文的正题。如果你没有看过上面提到的文章,建议最好先看一下,以便了解本文内容的背景,这样对于理解本文所讨论的东西会更有帮助。
话说在第六期的“VC6中使用CHtmlView在对话框控制中显示HTML文件”一文中,主要讨论并示范了如何改进 MFC 的 CHtmlView 类,使它能处理基于对话框的应用和各种其它类型的窗口应用,其思路是通过创建 CHtmlView 的派生类 CHtmlCtrl,使得 CHtmlView 摆脱了对文档/视图的依赖。
在第十一期的“如何禁用HTML页面的上下文菜单”一文中,主要讨论了如何通过子类化 IE 服务器窗口(Internet Explorer_Server)来禁用 CHtmlCtrl 的上下文菜单。实际上,真正显示HTML的窗口并不是浏览器(CHtmlView/CHtmlCtrl)窗口,而是一个名为“Internet Explorer_Server”的最底层的子孙窗口。这一点可以通过 Spy++ 来证实,为了获得该窗口的句柄(HWND),在实现过程中使用了一个函数 GetLastChild(HWND
hwndParent),其定义如下:
01.staticHWNDGetLastChild(HWNDhwndParent)
HWNDhwnd = hwndP
while(TRUE) {
HWNDhwndChild = ::GetWindow(hwnd, GW_CHILD);
if(hwndChild==NULL)
hwnd = hwndC
returnNULL;
通过这个函数返回某个父窗口下的最后一个子窗口,也就是说返回子窗口的子窗口的子窗口......直到不再有子窗口为止。可惜这个函数要获得正确的运行结果是有前提的,那就是窗口层次只能是一层,并且最终的窗口后裔是“Internet Explorer_Server”窗口。 在通常情况下,这个假设都成立。不幸的是,如果 HTML 文档中包含象 ComBoxes(组合框) 这样的控制时,这个假设就不灵了。用 Spy++ 不难发现情况并不象你期望的那样─Internet Explorer_Server是最后的子窗口。实际上,在IE中,Edit
和 Button 控制并非人们所想象的那样是子窗口。
获得 Win32 窗口句柄的更好的方法
为了解决这个问题,本文设计了一个更加完善的类:CFindWnd,用更好的专门来获取 IE 窗口。CFindWnd 查找某个窗口(给定窗口名字)的第一个子窗口。 例如,它的使用方法如下:
1.CFindWnd ies(m_hWnd,"Internet Explorer_Server");
2.myHwndIE = ies.m_hW
这个类的构造函数调用函数:
1.FindChildClassHwnd(hwndParent, (LPARAM)this)
函数,该函数又调用:
1.EnumChildWindows 和 FindWindowEx
搜索所有后裔窗口直到找到类名匹配窗口为止。FindWindow 用来查找最顶层窗口,而搜索子窗口还得用 FindWindowEx,它是 Win32 API 函数。CFindWnd 返回第一个匹配的窗口,所以它只被用于查找你期望只有一个实例的窗口。通常在搜索特定窗口时,一般最保险的做法都是检查窗口类名。
有一个读者来信指出:根本没有必要使用子类IE窗口的方法来禁用上下文菜单。完全可以在 CHtmlCtrl 内部实现,象下面这样:
1.BOOLCHtmlCtrl::PreTranslateMessage(MSG* pMsg)
if(pMsg-&message == WM_CONTEXTMENU)
returnTRUE;
returnCHtmlView::PreTranslateMessage(pMsg);
这样做是可行的,因为MFC实现了非常有独创性的、强大的特性─在 CWinThread 的主消息泵中,MFC 调用 CWnd::WalkPreTranslateTree 函数。这个函数循环消息目的地窗口的所有父窗口,调用每一个父窗口的 PreTranslateMessage ,一旦截获消息发送到后裔窗口则停止循环。非常聪明!
经验证明:要使前面的代码段按照期望的结果运行,你还必须截获 WM_RBUTTONDOWN 和 WM_RBUTTONDBLCLK 消息,同时还要做必要的检查以保证目标窗口的类名是 “Internet Explorer_Server”,这样就不会意外地捕获其它子窗口的上下文菜单(除非你确实要这么做)。下面是 CHtmlCtrl::PreTranslateMessage 的最终代码:
001.头文件 HtmlCtrl.h
004.#pragma once
013.structHTMLCMDMAP {
021.classCHtmlCtrl :publicCHtmlView
022.protected:
HTMLCMDMAP* m_
BOOLm_bHideM
025.<code clas
&&&&推荐文章:
【上篇】【下篇】}

我要回帖

更多关于 mfcclub会员登录界面 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信