该函数的参数为一个指向MEASUREITEMSTRUCT结构的指针对象,该对象结构为:
typedef struct tagMEASUREITEMSTRUCT {
UINT CtlType//控件类型;
UINT CtlID//控件的ID识别号,它不包括菜单控件;
UINT itemID//菜单项的ID识别号;
UINT itemWidth//菜单项的宽度;
UINT itemHeight//菜单项的高度;
DWORD itemData //自绘控件所需要的数据,
} MEASUREITEMSTRUCT
CMemuEx类除了上述介绍的需要重载的DrawItem()、MeasureItem()等函数外,另外的一些主要成员函数如下:
1、void InitMenu(CMenu *pMenu,UINT uToolBar,CToolBar *pToolBar)
说明:这是CMenuEx类最主要的一个接口。该函数根据状态栏信息来初始化CMenuEx类;
2、void SetImageLeft(UINT idBmpLeft);
说明:这也是CMenuEx类中的一个重要的接口。调用CMenuEx类对象的SetImageLeft()可以实现菜单中的纵向位图(像Windows系统中的"开始"菜单),调用该函数时参数是位图的ID值。需要注意的是,目前CMenuEx类实现的是对主框架菜单设置纵向位图,对上下文菜单不适用,读者朋友可以稍加修改,自由的决定对何种菜单设置纵向位图。
3、void InitPopupMenu(CMenu *pMenu,UINT uToolBar,CToolBar *pToolBar)
说明:这个函数是为了处理上下文菜单的自绘而编写的,CMenuEx类的任一实例都只能调用InitMenu()、InitPopupMenu()这两个成员函数中的一个,不能一同使用。
4、int GetImageFromToolBar(UINT uToolBar, CToolBar *pToolBar,COLORREF crMask)
说明:这个函数用来从工具条上获取相应图标。
5、void ChangeStyle(CMenu *pMenu,CToolBar *pToolBar,BOOL bIsMainMenu)
说明:这个函数用来修改菜单pMenu的类型为"自绘制"
6、void DrawMenuItemImage(CDC *pDC,CRect &rect,BOOL bSelected,BOOL bChecked,BOOL bGrayed,BOOL bHasImage,LPMENUITEM lpItem)
说明:这个函数根据菜单的不同状态及包含的各种信息,对菜单进行绘制;
上述函数构成了CMenuEx类的主要骨架,该类还有一些实现辅助函数,它们分别是:
1、void SetHighLightColor(COLORREF crColor)//设置菜单搞亮显示;
2、void SetBackColor(COLORREF)//设置菜单的背景颜色;
3、void SetTextColor(COLORREF)//设置菜单的文本颜色;
4、void GrayString(CDC *pDC,const CString &str,const CRect rect)//显示灰色菜单文本;
5、void TextMenu(CDC *pDC,CRect &rect,CRect rtText,BOOL bSelected,BOOL bGrayed,LPMENUITEM lpItem)//显示菜单上的文本;
CMenuEx类在使用过程中,要注意对其初始化,对于主框架菜单,可以在CMainFrame类的WM_INITMENU消息响应函数中实现,为了激活菜单的自绘功能, 需要在CMainFrame类的WM_DRAWITEM和WM_MEASUREITEM中分别调用CMenuEx类的DrawItem()函数和MeasureItem()函数。
LZ好,利用Visual C++打造自己的IE浏览器IE浏览器作为微软Windows系统捆绑销售的一个浏览工具,用来浏览千姿百态的网页,目前它已经占据了浏览器市场的半壁江山,成为Windows用户不可或缺的工具。首先,它的界面设计的很漂亮,如扁平按纽(按钮上的图像为灰色,当鼠标放在按钮上时,按钮突起,这种状态称为手柄,并且其上的图像变得鲜艳醒目)、按钮上的文字说明以及按钮边上的小黑三角形状的下拉箭头(单击时显示下拉菜单)、工具条上的地址输入栏等,都体现了Windows2000的风格;其次,它的收藏栏可以收藏用户喜爱的网络地址,这一切都为IE的流行打下了坚实的基础。说了那么多,也许读者朋友们感觉到IE实现起来一定非常困难,其实IE也是个"纸老虎",实现它的难点主要是在界面效果和显示收藏夹上,笔者在本实例中有针对性的叙述了IE界面、收藏网页的显示、网页的浏览等功能的实现,仔细看过这篇文章后,相信读者朋友们一定可以打造出一个属于自己的浏览器。本实例中的程序代码编译运行后的界面效果如图一所示:
图一、浏览器的运行界面
一、实现方法
1、浏览器的界面实现
首先启动Visual C++6.0,生成一个名为mfcie单文档项目,注意在此过程中不要选择工具条和状态条选项,这样才能更方便我们在后续工作中用代码实现Windwos2000风格的工具条、状态条;在工具条中添加地址栏;项目的视图类的基类设置为ChtmlView,该类的Navigate2()成员函数专门用来现实超文本格式的文档。在主框架类CmainFrame中定义CStatusBar m_wndStatusBar(状态条对象)、CToolBar m_wndToolBar(工具栏对象)、CReBar m_wndReBar(、CComboBoxEx m_wndAddress(扩展的组合框对象,用来作为地址栏)、CAnimateCtrl m_wndAnimate(动画控件,用来在工具栏上显示动画)、图像列表对象CImageList img(存放显示在工具栏上的图标)等对象。向当前项目AVI资源文件,ID标志IDR_MFCAVI,添加Bitmap(位图)资源,ID标志分别为IDB_COLDTOOLBAR、IDB_HOTTOOLBAR,分别如下所示:
图二、包含按钮图标的位图
1)IE风格工具条
IE风格界面的实现主要在主框架类的CMainFrame::OnCreate()函数中实现,它的主要思想如下: CReBar对象用来作为工具条、地址栏、动画控件的容器,CImageList对象然后分别装载工具栏上按钮的热点图像和正常状态下显示的图像,并将该对象附给工具条对象,使之建立关联。为了显示扁平工具栏,需要用CreateEx()函数创建CToolBar对象m_wndToolBar,用ModifyStyle()函数将工具栏的风格设为扁平类型,注意这里不能用CToolBar::Create() 或 CToolBar:: SetBarStyle()设置这种新风格。CToolBar 类不支持TBSTYLE_FLAT,要解决这个问题,必须绕过CToolBar类,使用CWnd::ModifyStyle()。要将某一个工具栏按钮设置为附带有下拉按钮,可以调用SetButtonInfo()设置按钮的风格为TBSTYLE_DROPDOWN。至于按钮带有中文提示,用工具栏的SetButtonText()就可以轻松实现了。下面是实现IE风格界面的代码和注释:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
CImageList img//图像列表对象;
CString str//字符串对象;
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1
if (!m_wndReBar.Create(this)) //创建CReBar对象;
{ TRACE0("Failed to create rebar\n")
return -1}
if (!m_wndToolBar.CreateEx(this)) //使用CreateEx()函数创建工具条对象;
{ TRACE0("Failed to create toolbar\n")
return -1}
//设置工具栏中的按钮最大最小尺寸;
m_wndToolBar.GetToolBarCtrl().SetButtonWidth(50, 150)
//设置工具栏上的按钮支持下拉箭头风格;
m_wndToolBar.GetToolBarCtrl().SetExtendedStyle(TBSTYLE_EX_DRAWDDARROWS)
//向图像列表装载热点图像资源,IDB_HOTTOOLBAR为热点图像资源ID img.Create(IDB_HOTTOOLBAR, 22, 0, RGB(255, 0, 255))
m_wndToolBar.GetToolBarCtrl().SetHotImageList(&img)
img.Detach()
//图象列表装载正常状态的图像资源,IDB_COLDTOOLBAR为图像资源ID
img.Create(IDB_COLDTOOLBAR, 22, 0, RGB(255, 0, 255))
m_wndToolBar.GetToolBarCtrl().SetImageList(&img)
img.Detach()
//设置工具条为扁平风格
m_wndToolBar.ModifyStyle(0, TBSTYLE_FLAT | TBSTYLE_TRANSPARENT)
//设置工具条上的按钮个数为9个;
m_wndToolBar.SetButtons(NULL, 9)
// 装载字符串资源,设置按钮上的文本和按钮的标识号;
m_wndToolBar.SetButtonInfo(0, ID_GO_BACK, TBSTYLE_BUTTON, 0)
str.LoadString(IDS_BACK)
m_wndToolBar.SetButtonText(0, str)
m_wndToolBar.SetButtonInfo(1, ID_GO_FORWARD, TBSTYLE_BUTTON, 1)
str.LoadString(IDS_FORWARD)
m_wndToolBar.SetButtonText(1, str)
m_wndToolBar.SetButtonInfo(2, ID_VIEW_STOP, TBSTYLE_BUTTON, 2)
str.LoadString(IDS_STOP)
m_wndToolBar.SetButtonText(2, str)
m_wndToolBar.SetButtonInfo(3, ID_VIEW_REFRESH, TBSTYLE_BUTTON, 3)
str.LoadString(IDS_REFRESH)
m_wndToolBar.SetButtonText(3, str)
m_wndToolBar.SetButtonInfo(4, ID_GO_START_PAGE, TBSTYLE_BUTTON, 4)
str.LoadString(IDS_HOME)
m_wndToolBar.SetButtonText(4, str)
m_wndToolBar.SetButtonInfo(5, ID_GO_SEARCH_THE_WEB, TBSTYLE_BUTTON, 5)
str.LoadString(IDS_SEARCH)
m_wndToolBar.SetButtonText(5, str)
m_wndToolBar.SetButtonInfo(6, ID_FAVORITES_DROPDOWN,TBSTYLE_BUTTON | TBSTYLE_DROPDOWN, 6)
str.LoadString(IDS_FAVORITES)
m_wndToolBar.SetButtonText(6, str)
m_wndToolBar.SetButtonInfo(7, ID_FILE_PRINT, TBSTYLE_BUTTON, 7)
str.LoadString(IDS_PRINT)
m_wndToolBar.SetButtonText(7, str)
m_wndToolBar.SetButtonInfo(8, ID_FONT_DROPDOWN, TBSTYLE_BUTTON | TBSTYLE_DROPDOWN, 8)
str.LoadString(IDS_FONT)
m_wndToolBar.SetButtonText(8, str)
// 设置工具栏上的按钮尺寸和显示在按钮上的图标尺寸;
CRect rectToolBar
m_wndToolBar.GetItemRect(0, &rectToolBar)
m_wndToolBar.SetSizes(rectToolBar.Size(), CSize(30,20))
//创建组合框,用来作为地址栏;
if (!m_wndAddress.Create(CBS_DROPDOWN | WS_CHILD, CRect(0, 0, 200, 120), this, AFX_IDW_TOOLBAR + 1))
{ TRACE0("Failed to create combobox\n")
return -1}
//创建动画控件对象,并打开AVI资源IDR_MFCAVI;
m_wndAnimate.Create(WS_CHILD | WS_VISIBLE, CRect(0, 0, 10, 10), this, AFX_IDW_TOOLBAR + 2)
m_wndAnimate.Open(IDR_MFCAVI)
//将工具条、地址栏、动画控件等添加到CReBar对象中;
m_wndReBar.AddBar(&m_wndToolBar)
m_wndReBar.AddBar(&m_wndAnimate, NULL, NULL, RBBS_FIXEDSIZE | RBBS_FIXEDBMP)
str.LoadString(IDS_ADDRESS)
m_wndReBar.AddBar(&m_wndAddress, str, NULL, RBBS_FIXEDBMP | RBBS_BREAK)
//再次设置工具条风格,使之有工具栏提示功能;
m_wndToolBar.SetBarStyle(m_wndToolBar.GetBarStyle() | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_FIXED)
//设置状态条;
if (!m_wndStatusBar.Create(this) || !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT)))
{ TRACE0("Failed to create status bar\n")
return -1}
…….//实现"Favorites"菜单的部分,该部分在第二部分介绍;
return 0
}
2)工具条上的下拉菜单
当用户点击按钮上的下拉箭头时,将出现相应的菜单,为了实现这个功能,首先需要在CMainFrame.cpp文件的消息映射中添加消息映射:ON_NOTIFY(TBN_DROPDOWN, AFX_IDW_TOOLBAR, OnDropDown);在CmainFrame.h文件中添加消息映射函数声明:afx_msg void OnDropDown(NMHDR* pNotifyStruct, LRESULT* pResult);最后添加下面的代码:
void CMainFrame::OnDropDown(NMHDR* pNotifyStruct, LRESULT* pResult)
{
NMTOOLBAR* pNMToolBar = (NMTOOLBAR*)pNotifyStruct
CRect rect
// 得到下拉箭头的位置;
m_wndToolBar.GetToolBarCtrl().GetRect(pNMToolBar->iItem, &rect)
rect.top = rect.bottom
::ClientToScreen(pNMToolBar->hdr.hwndFrom, &rect.TopLeft())
if(pNMToolBar->iItem == ID_FONT_DROPDOWN)
//判断是否为选择字体的下拉箭头;
{
CMenu menu
CMenu* pPopup
menu.LoadMenu(IDR_FONT_POPUP)
pPopup = menu.GetSubMenu(0)
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, rect.left, rect.top + 1, AfxGetMainWnd())
}
else if(pNMToolBar->iItem == ID_FAVORITES_DROPDOWN)
{//判断是否为显示收藏网页的下拉箭头;
CMenu* pPopup
pPopup = GetMenu()->GetSubMenu(3)
pPopup->TrackPopupMenu(TPM_LEFTALIGN | TPM_LEFTBUTTON, rect.left,
rect.top + 1, AfxGetMainWnd())
}
*pResult = TBDDRET_DEFAULT
}
3)工具条上的动画实现
为了美化程序的界面,程序的复合工具条上放置了一个动画控件,用来在适当的时机播放一个动画片段,实现动画效果。下面的代码实现了创建动画控件对象,并打开AVI资源IDR_MFCAVI:
m_wndAnimate.Create(WS_CHILD | WS_VISIBLE, CRect(0, 0, 10, 10), this, AFX_IDW_TOOLBAR + 2)
m_wndAnimate.Open(IDR_MFCAVI)
CanimateCtrl类提供了Play()、Seek()、Stop()、Close()等函数用来为播放视频文件服务,它们使用起来都非常简单,这里就不再赘述了。
4)地址栏的 *** 作
当用户在地址栏上输入网页地址并按下回车键后,浏览器将显示该网页的内容,并将在地址栏中记录下该地址。因为回车键按下后对应的消息ID为IDOK,为此,需要在CmainFrame类中添加消息映射ON_COMMAND(IDOK, OnNewAddressEnter)和消息响应函数afx_msg void OnNewAddressEnter()。该函数实现代码如下:
void CMainFrame::OnNewAddressEnter()
{
CString str
//获取地址栏中的字符串;
m_wndAddress.GetEditCtrl()->GetWindowText(str)
((CMfcieView*)GetActiveView())->Navigate2(str, 0, NULL)//显示该网页;
//将该网址添加到地址栏对应的组合框中;
COMBOBOXEXITEM item
item.mask = CBEIF_TEXT
item.iItem = -1
item.pszText = (LPTSTR)(LPCTSTR)str
m_wndAddress.InsertItem(&item)
}
同理,还要在CmainFrame类中为地址栏(ID 为AFX_IDW_TOOLBAR + 1)添加消息映射ON_CBN_SELENDOK(AFX_IDW_TOOLBAR + 1,OnNewAddress)和消息响应函数OnNewAddress,用来处理用户从地址栏组合框中选择网址的 *** 作,该函数的实现代码如下:
void CMainFrame::OnNewAddress()
{
CString str
m_wndAddress.GetLBText(m_wndAddress.GetCurSel(), str)
((CMFCIEView*)GetActiveView())->Navigate2(str, 0, NULL)
}
2、实现收藏菜单
一般IE的用户都有个习惯,那就是将自己喜欢的网址保存起来,以方便今后快速的登陆,为了使我们的浏览器能够显示IE收藏过的网址,程序中设置了一个"Favorites"菜单,通过RegOpenKey()、RegQueryValueEx()等函数 *** 作Windows的注册表中的HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\User Shell Folders项,将收藏的网址显示到菜单上。为此,实例中定义了两个函数,实现代码如下所示:
TCHAR GetDir( ) //得到存放用户收藏网址的目录;
{
TCHAR sz[MAX_PATH]
TCHAR szPath[MAX_PATH]
HKEY hKey
DWORD dwSize
CMenu* pMenu
// 得到"Favorites"菜单,并删除空白的子菜单项;
pMenu = GetMenu()->GetSubMenu(3)
while(pMenu->DeleteMenu(0, MF_BYPOSITION))
// find out from the registry where the favorites are located.
if(RegOpenKey(HKEY_CURRENT_USER, _T("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\
User Shell Folders"), &hKey) != ERROR_SUCCESS)
{
TRACE0("Favorites folder not found\n")
return 0
}
dwSize = sizeof(sz)
RegQueryValueEx(hKey, _T("Favorites"), NULL, NULL, (LPBYTE)sz, &dwSize)
ExpandEnvironmentStrings(sz, szPath, MAX_PATH)
RegCloseKey(hKey)
Return szPath
}
int CMainFrame::BuildFavoritesMenu(LPCTSTR pszPath, int nStartPos, CMenu* pMenu)
{
CString strPath(pszPath)
CString strPath2
CString str
WIN32_FIND_DATA wfd
HANDLE h
int nPos
int nEndPos
int nNewEndPos
int nLastDir
TCHAR buf[INTERNET_MAX_PATH_LENGTH]
CStringArray astrFavorites
CStringArray astrDirs
CMenu* pSubMenu
if(strPath[strPath.GetLength() - 1] != _T(’\\’))
strPath += _T(’\\’)
strPath2 = strPath
strPath += "*.*"
// 扫描当前目录,首先搜索*.URL文件,然后是可能含有*.URL文件的子目录;
h = FindFirstFile(strPath, &wfd)
if(h != INVALID_HANDLE_VALUE)
{
nEndPos = nStartPos
do
{
if((wfd.dwFileAttributes&
(FILE_ATTRIBUTE_DIRECTORY|FILE_ATTRIBUTE_HIDDEN|FILE_ATTRIBUTE_SYSTEM))==0)
{
str = wfd.cFileName
if(str.Right(4) == _T(".url"))
{/*URL文件和INI文件格式类似,所以我们可以使用 GetPrivateProfileString() 来得到我们所需要的信息。*/
::GetPrivateProfileString(_T("InternetShortcut"), T("URL"),
_T(""),buf,INTERNET_MAX_PATH_LENGTH,
strPath2 + str)
str = str.Left(str.GetLength() - 4)
// 判断是否已经重复;
for(nPos = nStartPos nPos <nEndPos ++nPos)
{
if(str.CompareNoCase(astrFavorites[nPos]) <0)
break
}
astrFavorites.InsertAt(nPos, str)//添加该字符串;
m_astrFavoriteURLs.InsertAt(nPos, buf)//保留相应的地址
++nEndPos
}
}
} while(FindNextFile(h, &wfd))
FindClose(h)
// 将找到的项目添加到菜单中;
for(nPos = nStartPos nPos <nEndPos ++nPos)
{
pMenu->AppendMenu(MF_STRING | MF_ENABLED, 0xe00 + nPos, astrFavorites[nPos])
}
// 搜索子目录
nLastDir = 0
h = FindFirstFile(strPath, &wfd)
ASSERT(h != INVALID_HANDLE_VALUE)
do
{
if(wfd.dwFileAttributes &FILE_ATTRIBUTE_DIRECTORY)
{ //对目录进行搜索;
if(lstrcmp(wfd.cFileName,_T(".")) == 0 || lstrcmp(wfd.cFileName, _T("..")) == 0)
continue
for(nPos = 0 nPos <nLastDir ++nPos)
{
if(astrDirs[nPos].CompareNoCase(wfd.cFileName) >0)
break
}
pSubMenu = new CMenu
pSubMenu->CreatePopupMenu()
// call this function recursively.
nNewEndPos = BuildFavoritesMenu(strPath2 + wfd.cFileName, nEndPos, pSubMenu)
if(nNewEndPos != nEndPos)
{
// 插入子菜单;
nEndPos = nNewEndPos
pMenu->InsertMenu(nPos, MF_BYPOSITION | MF_POPUP | MF_STRING, (UINT)pSubMenu->m_hMenu, wfd.cFileName)
pSubMenu->Detach()
astrDirs.InsertAt(nPos, wfd.cFileName)
++nLastDir
}
delete pSubMenu
}
} while(FindNextFile(h, &wfd))
FindClose(h)
}
return nEndPos
}
3、显示超文本
微软ChtmView类的Navigate2函数可以实现超文本文件的显示,GoBack()、GoForward()等函数可以分别实现网页浏览的回退和前进 *** 作。以响应"Favorite"菜单项为例,需要在程序的CmainFrame类中添加消息映射ON_COMMAND_RANGE(0xe00, 0xfff, OnFavorite)和消息响应函数OnFavorite,来响应ID为0xe00-0xfff范围内的菜单单击处理,具体实现代码如下:
void CMainFrame::OnFavorite(UINT nID)
{
((CMFCIEView*)GetActiveView())->Navigate2(m_astrFavoriteURLs[nID-0xe00], 0, NULL)
}
二、编程步骤
1、 启动Visual C++6.0,生成一个单文档视图结构的应用程序,将该程序命名为"mfcie",注意在生成项目的过程中不要选择工具条和状态条选项,项目的视图类的基类设置为ChtmlView;
2、 按照上文中的说明,使用Class Wizard在程序的项目中添加相应的消息响应函数;
3、 向程序的项目中添加AVI、位图资源;
4、 添加代码,编译运行程序。 415希望对你有帮助!
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)