作者:刘志铭,李贺,高茹
出版社:人民邮电出版社
格式: AZW3, DOCX, EPUB, MOBI, PDF, TXT
Visual C++程序开发范例宝典(不提供光盘内容)试读:
前言
前些年,笔者参加了一个项目的开发工作,项目要求时间很紧,开发团队几乎是挑灯夜战。当时基于Windows的开发资料很少,网络也不发达,常常为了解决一个问题,大家连续奋战几天、十几天,甚至几十天。之后,笔者又参加了多个项目的开发工作。在开发过程中深刻地感觉到:编程是一门创造性较强的活动,因其涉及面广,开发者往往需要学习、研究各方面的技术和问题;编程水平的提高与开发时间成正比,需要长时间经验的积累和磨炼;编程是一项需要相互学习、相互交流的工作,在交流过程中,不但可分享他人的编程经验、体会,更会产生新的灵感,达到事半功倍的效果。
总之,项目开发从来不是一件容易的事,即使是非常有经验的开发人员,也经常会遇到一些技术难题。要成为一名合格的程序员,就必须不断吸取和借鉴其他开发者的成功经验。通过阅读别人编写的程序,从中吸取编程思想的精华,这也是学习程序设计最好的方法。
本书内容
本书精选了372个典型实例,所选实例覆盖了开发中的热点问题和关键问题。全书按实际应用进行分类,可以使读者在短时间内掌握更多有用的技术,快速提高编程水平。所选内容均来源于实际项目的开发,有的实例是作者开发实践的积累,有的实例来源于公司的开发项目,还有的来自读者的问题。通过对这些实例进行详细分析和讲解,可以让读者迅速掌握VisualC++程序设计的开发经验和技巧,迅速提高程序设计的综合水平。
全书分为15章,涵盖了窗体与界面设计,控件应用,图形技术,多媒体技术,文件系统,操作系统与Windows相关程序,注册表,数据库技术,SQL查询相关技术,打印与报表技术,硬件相关开发技术,网络开发技术,Web编程,加密、安全与软件注册,实用工具等方面的内容。
在实例讲解上,全书采用了统一的编排方式,每个实例都包括“实例说明”、“技术要点”、“实现过程”和“举一反三”4个部分。在“实例说明”中,以图文结合的方式给出了实例的功能说明及运行效果。在“技术要点”中给出了实例的重点、难点技术和相关编程技巧。在“实现过程”中介绍了该实例的设计过程和主要程序代码。在“举一反三”中给出了相关实例的扩展应用。
本书特色
● 所有实例内容都以解决开发人员在编程中遇到的实际问题和开发中应该掌握的技术为中心,每个实例都可以解决某一方面的问题。有的可以解决工作中的难题,有的可以提高工作效率,有的可以提升工作价值。
● 所选实例都具有极强的扩展性,能够给读者以启发,使读者举一反三,开发出非常实用的软件。
● 所选实例都具有代表性,所有实例都提供了源代码,方便读者使用。
● 本书光盘中提供了本书实例的“源码速查电子搜索引擎”,读者可以快速检索所需技术和代码。
本书的约定
书中每个实例的标题栏都给出了程序的特色和所在光盘中的路径,读者可根据需要学习和使用。
书中涉及数据库的实例,在实例对应文件夹中均提供了数据库文件或数据库文件路径。
书中可能多个实例用到了同一主要技术,为节省篇幅,相关技术的讲解只在一个实例中介绍。
因篇幅限制,书中实例只给出了关键代码,其他代码参见光盘中实例的源程序。
使用本书实例光盘前,请仔细阅读光盘中的“光盘使用说明”。
本书的服务
本书由明日科技组织编写,参加编写的有王小科、王国辉、崔佳音、周佳星、张鑫、辛洪郁、赛奎春、高春艳、杨丽、陈英、刘佳、刘丽艳、刘红艳、孙雨婷等。由于作者水平有限,错漏之处在所难免,请广大读者批评指正。
如果读者在使用本书时遇到问题,可以访问明日科技网站,我们将通过该网站全面为读者提供网上服务和支持。对于读者使用本书时遇到的问题,我们将在5个工作日内回复。
服务网站:www.mingribook.com
服务信箱:mingrisoft@mingrisoft.com
服务电话:4006751066编者2014年11月
第1章 窗体与界面设计
菜单应用实例
弹出菜单应用实例
工具栏应用实例
状态栏应用实例
导航界面应用实例
界面窗体应用实例
多媒体宣传光盘应用实例
多媒体触摸屏程序应用实例
窗体位置应用实例
窗体标题栏应用实例
窗体形状及应用
通用对话框的应用
1.1 菜单应用实例
在设计程序主界面时,菜单几乎是必不可少的界面元素之一。在MFC中,提供了CMenu类用于操作和管理菜单。本节将通过几个典型实例介绍各种常用菜单的设计。实例001 在系统菜单中添加菜单项
这是一个可以提高基础技能的实例
实例位置:光盘\mingrisoft\01\001
实例说明
系统菜单是用户右击标题栏时弹出的快捷菜单。默认情况下,系统菜单只包含移动、关于和与标题栏按钮对应的菜单项,如何在系统菜单中添加自己的菜单项呢?本实例实现了该功能,效果如图1.1所示。图1.1 在系统菜单中添加菜单项
技术要点
为了操作系统菜单,首先需要获取一个系统菜单指针,可以通过GetSystemMenu函数实现,然后利用菜单指针添加一个菜单项,最后在对话框的OnSysCommand方法中处理菜单项的命令。
GetSystemMenu方法用于获取一个系统菜单指针,语法如下:
CMenu* GetSystemMenu( BOOL bRevert ) const;
参数说明:
● bRevert:确定方法执行的动作,如果为FALSE,该方法返回当前正在使用的系统菜单;如果为TRUE,该方法将重新设置系统菜单到默认状态,并且方法返回值不可用。
实现过程(1)新建一个基于对话框的应用程序。(2)在对话框类中定义一个菜单指针m_pMenu,用于指向系统菜单。(3)主要程序代码。
在对话框初始化时(OnInitDialog函数中)获取系统菜单指针,向系统菜单中添加菜单项,代码如下:
m_pMenu=GetSystemMenu(FALSE); //获得正在使用的系统菜单指针
m_pMenu->AppendMenu(MF_STRING,IDI_PECULIARMENU,"系统菜单"); //添加菜单项
响应菜单项的命令消息,在对话框的OnSysCommand方法中添加消息处理代码:void CPeculiarMenuDlg::OnSysCommand(UINTnID,LPARAMlParam){if ((nID) ==IDM_ABOUTBOX){CAboutDlg dlgAbout;dlgAbout.DoModal();}else if (nID== IDI_PECULIARMENU) //如果是添加的菜单项{MessageBox("系统菜单","提示",MB_OK|MB_ICONINFORMATION); //弹出消息提示}else{CDialog::OnSysCommand(nID,lParam);}}
举一反三
根据本实例,读者可以:
禁用系统菜单项。实例002 带图标的程序菜单
本实例是一个人性化的实例
实例位置:光盘\mingrisoft\01\002
实例说明
在MFC应用程序中,默认情况下,CMenu类并不具有显示图标的功能,但在许多应用程序中,菜单中都带有漂亮的图标。那么如何在MFC应用程序中为菜单添加图标呢?本实例实现了该功能,效果如图1.2所示。图1.2 带图标的程序菜单
技术要点
要实现带图标的菜单,需要从CMenu类派生一个子类,并在子类中改写DrawItem方法和MeasureItem方法。基本设计思路如下。
首先定义一个记录菜单项信息的结构CMenuItemInfo,该结构包含了菜单项的文本、图像索引、ID等信息。然后从CMenu中派生一个子类,本实例为CIconMenu。在该类中定义一个方法ChangeMenuItem,利用递归的方式修改所有的菜单项信息,使其具有自绘风格(MF_OWNERDRAW)。接着在CIconMenu类中定义绘制菜单项文本、绘制菜单项图标和绘制分隔条的方法。最后改写 MeasureItem 方法,设置菜单项的大小,改写DrawItem方法,根据菜单项的不同状态,绘制菜单项。
实现过程(1)新建一个单文档/视图结构的应用程序。(2)从CMenu类派生一个子类CIconMenu。(3)定义一个菜单项结构CMenuItemInfo,代码如下:/*************************************CMenuItemInfo结构用于记录菜单项信息*************************************/struct CMenuItemInfo{CStringm_ItemText; //菜单项文本intm_IconIndex; //菜单项索引intm_ItemID; //菜单标记 −2顶层菜单,−1弹出式菜单,0分隔条,其他普通菜单};(4)在CIconMenu类中定义一个CImageList类型的成员变量m_imagelist,用于存储图像;定义一个CMenuItemInfo结构数组m_ItemLists,用于记录每个菜单项信息。(5)在CIconMenu类的构造函数中创建图像列表,并向图像列表中添加图标,代码如下:CIconMenu::CIconMenu(){m_index=0;m_iconindex=0;//创建图像列表m_imagelist.Create(16,16,ILC_COLOR24|ILC_MASK,0,0);//添加图标m_imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON1));m_imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON2));m_imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON3));m_imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON4));m_imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON5));m_imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON6));m_imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON7));m_imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON8));m_imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON9));m_imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON10));}(6)向CIconMenu类中添加ChangeMenuItem方法,修改菜单项信息,代码如下:BOOLCIconMenu::ChangeMenuItem(CMenu* m_menu,BOOLm_Toped){if(m_menu!=NULL){intm_itemcount=m_menu->GetMenuItemCount(); //获得菜单项目数for (int i=0;i
举一反三
根据本实例,读者可以:
实现具有状态栏提示功能的菜单。实例003 浮动的菜单
这是一个可以提高分析能力的实例
实例位置:光盘\mingrisoft\01\003
实例说明
在许多应用软件中,菜单都具有浮动功能。例如在 Word 中,用户可以将菜单拖动到任意位置。本实例设计了一个浮动的菜单,效果如图1.3所示。图1.3 浮动的菜单
技术要点
在文档/视图结构的应用程序中,默认情况下,工具栏具有拖动菜单的功能。在用户单击工具栏按钮时,能够弹出一个快捷菜单,就可以实现一个浮动的“菜单”了,如何确定用户是否单击了工具栏按钮呢,可以通过在框架窗口中添加TBN_DROPDOWN通知消息映射宏来实现。
ON_NOTIFY(TBN_DROPDOWN,AFX_IDW_TOOLBAR,OnToolbarDropDown)
这样,当用户单击工具栏按钮时,就会调用自定义的OnToolbarDropDown方法,在该方法中可以获得用户单击的工具栏按钮ID和按钮的客户区域,根据按钮ID加载相应的子菜单,根据按钮区域设置子菜单弹出的位置。
实现过程(1)新建一个文档/视图应用程序。(2)从CToolBar类派生一个子类CFloatMenu。在 CFloatMenu中定义一个CMenu指针m_pSubMenu。(3)向CFloatMenu类中添加AddButtonFromMenu方法,该方法根据菜单添加工具栏按钮,代码如下:BOOLCFloatMenu::AddButtonFromMenu(UINTIDresource){CMenuMenu;if(Menu.LoadMenu(IDresource)){//获取菜单顶层菜单数UINTButtonCount =Menu.GetMenuItemCount();UINT* array= newUINT[ButtonCount];CString text;for (intn =0; n ON_NOTIFY(TBN_DROPDOWN,AFX_IDW_TOOLBAR,OnToolbarDropDown)(6)在框架类中添加OnToolbarDropDown方法,在用户单击工具栏按钮时弹出菜单,代码如下:void CMainFrame::OnToolbarDropDown(NMTOOLBAR *pnmtb,LRESULT*plr){CWnd* pWnd=&m_wndFloatTool; //获得浮动工具栏窗口指针UINTnID =IDR_MAINFRAME;CMenu menu;menu.LoadMenu(nID); //加载菜单资源CMenu* pPop=menu.GetSubMenu(pnmtb->iItem-ID_BUTTON1);//获得子菜单m_wndFloatTool.m_pSubMenu =pPop;m_wndFloatTool.MenuPopIndex=pnmtb->iItem-ID_BUTTON1;//设置菜单索引CRect rc;m_wndFloatTool.GetToolBarCtrl().GetItemRect(pnmtb->iItem-ID_BUTTON1,rc);//获得工具栏按钮区域pWnd->ClientToScreen(&rc); //转换为屏幕坐标区域pPop->TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_VERTICAL,rc.left,rc.bottom,this,&rc); //显示弹出菜单m_wndFloatTool.MenuPopIndex =-1;} 举一反三 根据本实例,读者可以: 设计浮动的对话框窗口。 1.2 弹出菜单应用实例
在程序中使用弹出式菜单能够方便用户操作。本节通过几个典型实例介绍各种弹出式菜单的设计。实例004 在控件上单击右键弹出菜单
本实例可以方便操作、提高效率
实例位置:光盘\mingrisoft\01\004
实例说明
在许多应用软件中,当用户单击鼠标右键时,会弹出一个快捷菜单,用户可以通过快捷菜单方便地进行各种操作。本实例实现了弹出式菜单的功能,效果如图1.4所示。
技术要点
实现弹出式菜单非常简单,只需要处理WM_CONTEXTMENU消息就可以了。在其消息处理函数(默认为OnContextMenu)中调用菜单的TrackPopupMenu方法即可在指定位置弹出菜单。
实现过程(1)新建一个基于对话框的应用程序。(2)在对话框中添加List Control 控件,设置控件属性,如图1.5 所示。图1.4 在控件上单击右键弹出菜单图1.5 列表控件属性(3)处理对话框的WM_CONTEXTMENU消息,代码如下:void CPopManuDlg::OnContextMenu(CWnd* pWnd,CPoint point){CMenum_popmenu; //定义菜单对象m_popmenu.LoadMenu(IDR_POPMENU); //加载菜单资源CMenu*m_submenu=m_popmenu.GetSubMenu(0); //获得子菜单m_submenu->TrackPopupMenu(TPM_LEFTBUTTON |TPM_LEFTALIGN ,point.x,point.y,this); //显示弹出菜单m_popmenu.DestroyMenu();}
举一反三
根据本实例,读者可以:
设计系统托盘菜单。实例005 个性化的弹出菜单
这是一个可以提高基础技能的实例
实例位置:光盘\mingrisoft\01\005
实例说明
网上许多软件的弹出式菜单非常漂亮。本实例设计了一个漂亮的弹出式菜单,效果如图1.6所示。图1.6 个性化的弹出菜单
技术要点
设计弹出式菜单与设计普通的菜单一样,需要从 CMenu 类派生一个子类,然后改写MeasureItem方法设置菜单项大小;改写DrawItem方法根据当前状态绘制菜单。设计思路可以参考实例002带图标的程序菜单。
实现过程(1)新建一个基于对话框的应用程序。(2)CMenu派生一个子类CIconMenu,定义一个菜单项结构CMenuItemInfo,代码如下:/*************************************CMenuItemInfo结构用于记录菜单项信息*************************************/struct CmenuItemInfo{CStringm_ItemText; //菜单项文本intm_IconIndex; //菜单项索引intm_ItemID; //菜单标记 −2顶层菜单,−1弹出式菜单,0分隔条,其他普通菜单};(3)在CIconMenu类中定义如下成员变量:
CMenuItemInfom_ItemLists[MAX_MENUCOUNT]; //菜单项信息
intm_index; //临时索引
intm_iconindex; //图像索引
BOOLm_isdrawtitle; //是否重绘标题
CFontm_titlefont; //标题字体(4)向CIconMenu类中添加DrawItemText方法,绘制菜单项文本,代码如下:/*************************************************************功能描述:绘制菜单项文本参数说明:m_pdc标识画布对象,str标识菜单文本,m_rect标识菜单区域*************************************************************/void CIconMenu::DrawItemText(CDC* m_pdc,LPSTRstr,CRect m_rect){m_rect.DeflateRect(40,0,0,0); //调整文本绘制区域m_pdc->DrawText(str,m_rect,DT_SINGLELINE|DT_VCENTER|DT_LEFT); //绘制菜单项文本}(5)向CIconMenu类中添加DrawComMenu方法,绘制普通的菜单,代码如下:void CIconMenu::DrawComMenu(CDC* m_pdc,CRect m_rect,COLORREF m_fromcolor,COLORREFm_tocolor,BOOLm_selected ){if (m_selected) //如果选中菜单项{m_pdc->SelectStockObject(BLACK_PEN); //设置黑色画笔m_rect.DeflateRect(25,1,0,2); //调整菜单项区域m_pdc->Rectangle(m_rect); //绘制矩形CBitmap m_bitmap;m_bitmap.LoadBitmap(IDB_LEFTBITMAP); //加载位图资源BITMAPm_size;m_bitmap.GetBitmap(&m_size); //获得位图数据CDC m_memdc;m_memdc.CreateCompatibleDC(m_pdc); //创建内存兼容设备上下文CGdiObject* m_oldobject;m_oldobject=m_memdc.SelectObject(&m_bitmap); //选入位图m_pdc->StretchBlt(m_rect.left+1,m_rect.top+1,m_rect.Width()-2,m_rect.Height()-2,&m_memdc,0,0,m_size.bmWidth, m_size.bmHeight,SRCCOPY); //绘制位图m_bitmap.DeleteObject();}else{m_pdc->FillSolidRect(m_rect,RGB(0x000000F9,0x000000F8,0x000000F7));//填充菜单项背景}}(6)向CIconMenu类中添加DrawSeparater方法,绘制分隔条,代码如下:void CIconMenu::DrawSeparater(CDC* m_pdc,CRect m_rect){if(m_pdc!=NULL){m_rect.DeflateRect(25,0,0,0); //设置绘制区域m_pdc->Draw3dRect(m_rect,RGB(255,0,0),RGB(0,0,255)); //绘制滚动条}}(7)向CIconMenu类中添加ChangeMenuItem方法,修改菜单项的风格,代码如下:BOOLCIconMenu::ChangeMenuItem(CMenu* m_menu,BOOLm_Toped){if(m_menu!=NULL){intm_itemcount=m_menu->GetMenuItemCount(); //获得菜单项数量for (int i=0;i
举一反三
根据本实例,读者可以:
开发具有背景颜色的菜单。实例006 任务栏托盘弹出菜单
本实例是一个提高效率、人性化的程序
实例位置:光盘\mingrisoft\01\006
实例说明
在安装完瑞星、金山词霸等软件时,在系统的任务栏中会显示一个托盘图标。用户用鼠标右键单击托盘图标,就会弹出一个快捷菜单。本实例将实现一个任务栏托盘菜单,效果如图1.7所示。图1.7 任务栏托盘弹出菜单
技术要点
要设计任务栏托盘菜单,需要使用Shell_NotifyIcon函数。该函数语法如下:WINSHELLAPI BOOL WINAPI Shell_NotifyIcon(DWORD dwMessage,PNOTIFYICONDATA pnid);
参数说明:
● dwMessage:表示发送的消息值,其可选值如下。
■ NIM_ADD:表示添加图标到任务栏。
■ NIM_DELETE:表示从任务栏区域删除一个图标。
■ NIM_MODIFY:表示修改任务栏区域的一个图标。
● pnid:是NOTIFYICONDATA 结构指针。
NOTIFYICONDATA结构定义如下:typedef struct_NOTIFYICONDATA{DWORD cbSize;HWNDhWnd;UINTuID;UINTuFlags;UINTuCallbackMessage;HICONhIcon;char szTip[64];}NOTIFYICONDATA,*PNOTIFYICONDATA;
参数说明:
● cbSize 确定NOTIFYICONDATA 结构的大小。
● hWnd 表示接收任务栏菜单消息的窗口句柄。
● uID 表示任务栏图标标识符。
● uFlags 确定NOTIFYICONDATA 结构中哪些成员是合法的。
● uCallbackMessage 表示应用程序定义的消息标识符,系统将要发送该消息到hWnd 表示的窗口。
● hIcon 表示添加、修改或删除的图标句柄。
● szTip 是工具提示文本。
实现过程(1)新建一个基于对话框的应用程序。(2)从CMenu类派生一个子类CIconMenu,改写DrawItem方法和MeasureItem方法重新绘制菜单。(3)在对话框类中定义一个NOTIFYICONDATA结构变量m_traydata,在OnInitDialog方法中初始化m_traydata。
m_traydata.cbSize= sizeof(NOTIFYICONDATA); //设置结构大小
m_traydata.hIcon=AfxGetApp()->LoadIcon(IDI_TRAYICON); //加载图标资源
m_traydata.hWnd=m_hWnd; //设置窗口句柄
char *m_str= "系统管理"; //声明字符串
//strlen +1表示将空字符复制到目标字符串中
strncpy(m_traydata.szTip,m_str,strlen(m_str)+1); //复制字符串
m_traydata.uCallbackMessage=WM_TRARMESSAGE; //设置回传消息
m_traydata.uFlags=NIF_ICON|NIF_MESSAGE|NIF_TIP; //设置合法参数(4)在对话框的OnSysCommand方法中判断用户是否单击了“最小化”按钮,如果是,隐藏对话框,调用Shell_NotifyIcon函数向任务栏中添加图标,代码如下:void CTrayPopMenuDlg::OnSysCommand(UINTnID,LPARAMlParam){if((nID&0xFFF0)==IDM_ABOUTBOX){CAboutDlgdlgAbout;dlgAbout.DoModal();}else if ((nID& 0xFFF0) ==SC_MINIMIZE) //如果是最小化消息{ShowWindow(SW_HIDE); //隐藏窗口Shell_NotifyIcon(NIM_ADD,&m_traydata); //添加系统托盘图标}else{CDialog::OnSysCommand(nID,lParam);}}(5)在对话框的消息映射部分添加映射宏。
ON_MESSAGE(WM_TRARMESSAGE,OnTrayMessage)(6)向对话框中添加OnTrayMessage方法,代码如下:void CTrayPopMenuDlg::OnTrayMessage(WPARAMwParam, LPARAMlParam){if (lParam==WM_LBUTTONDOWN) //如果在托盘图标上单击鼠标左键{ShowWindow(SW_RESTORE); //恢复显示窗口}else if (lParam==WM_RBUTTONDOWN) //如果在托盘图标上单击鼠标右键{CPointm_point;::GetCursorPos(&m_point); //获得鼠标当前位置CIconMenu*m_submenu= (CIconMenu*)m_menu.GetSubMenu(0); //获得子菜单m_submenu->TrackPopupMenu(TPM_LEFTALIGN|TPM_RIGHTBUTTON,m_point.x,m_point.y,AfxGetApp()->m_pMainWnd,TPM_LEFTALIGN); //显示弹出菜单}}
举一反三
根据本实例,读者可以:
修改和删除系统托盘菜单。
1.3 工具栏应用实例
工具栏是应用程序界面的重要组成元素之一,它包含了一组命令按钮,用于执行某些菜单项的功能。通常情况下,将应用程序中常用的功能放置在工具栏中,这样可以方便用户操作,省去了在级联菜单中层层查找菜单项的困扰。在MFC类库中,CToolBar类封装了工具栏的基本功能,在本节中,将详细介绍利用CToolBar类设计各种工具栏。
工具栏在开发应用程序时经常用到,本节将介绍几种特色工具栏的实现方法。实例007 带图标的工具栏
这是一个可以启发思维的实例
实例位置:光盘\mingrisoft\01\007
实例说明
默认情况下,MFC中提供的工具栏只能显示简单的图像。本实例实现了一个带有图标的工具栏按钮,效果如图1.8所示。图1.8 带图标的工具栏
技术要点
工具栏CToolBar提供了一个GetToolBarCtrl方法,用于获得一个 CToolBarCtrl 对象,该对象提供了一个SetImageList方法,用于设置与工具栏关联的图像列表控件。只要在程序中创建一个图像列表,并向图像列表中添加图标,将其与工具栏关联,那么工具栏按钮就会显示出图像。
实现过程(1)新建一个文档/视图结构的应用程序。(2)在框架类中定义一个CImageList对象m_Imagelist。(3)在框架类的OnCreate方法中创建图像列表,并向图像列表中添加图标。创建工具栏,将工具栏与图像列表关联,设置工具栏按钮的大小,代码如下:int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct){if(CFrameWnd::OnCreate(lpCreateStruct)==-1)return -1;//创建图像列表,向图像列表中添加图标m_Imagelist.Create(32,32,ILC_COLOR24|ILC_MASK,0,1);for (int i=0;i<9;i++){m_Imagelist.Add(AfxGetApp()->LoadIcon(IDI_ICON1+i));//加载图标资源}//创建工具栏if (!m_wndToolBar.CreateEx(this,TBSTYLE_FLAT,WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_GRIPPER|CBRS_TOOLTIPS |CBRS_FLYBY|CBRS_SIZE_DYNAMIC) ||!m_wndToolBar.LoadToolBar(IDR_MAINFRAME)){TRACE0("Failedtocreatetoolbar\n");return -1; // fail to create}m_wndToolBar.GetToolBarCtrl().SetImageList(&m_Imagelist); //管理图像列表m_wndToolBar.GetToolBarCtrl().SetButtonSize(CSize(40,40)); //设置按钮大小m_wndToolBar.GetToolBarCtrl().SetBitmapSize(CSize(30,30)); //设置图像大小if (!m_wndStatusBar.Create(this)||!m_wndStatusBar.SetIndicators(indicators,sizeof(indicators)/sizeof(UINT))){TRACE0("Failedtocreatestatusbar\n");return -1; // fail to create}m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);EnableDocking(CBRS_ALIGN_ANY);DockControlBar(&m_wndToolBar);return 0;}
举一反三
根据本实例,读者可以:
实现具有热点效果的工具栏。实例008 带下拉菜单的工具栏
本实例可以美化界面、简化操作
实例位置:光盘\mingrisoft\01\08
实例说明
本实例是对工具栏功能的扩充,可以将工具栏上按钮的并列项以菜单的形式显示,方便用户操作。运行程序,单击工具栏按钮旁边的下三角按钮,将弹出一个下拉菜单,如图1.9所示。图1.9 带下拉菜单的工具栏
技术要点
下三角按钮是通过 CToolBar 类的 SetButtonStyle 方法和CToolBarCtrl类的SetExtendedStyle方法实现的。
SetButtonStyle方法用来设置工具栏按钮的风格,语法如下:
voidSetButtonStyle(intnIndex,UINTnStyle);
参数说明:
● nIndex:按钮的索引。
● nStyle:按钮的风格。可以有以下取值。
■ TBBS_BUTTON:标准按钮。
■ TBBS_SEPARATOR:分隔线。
■ TBBS_CHECKBOX:复选风格。
■ TBBS_GROUP:按钮组。
■ TBBS_CHECKGROUP:复选按钮组。
SetExtendedStyle方法用于设置工具栏控件的扩展风格,语法如下:
DWORDSetExtendedStyle( DWORDdwExStyle) const;
参数说明:
● dwExStyle:系统定义的工具栏控件风格,取值TBSTYLE_EX_DRAWDDARROWS,可以实现下三角按钮功能。
实现过程(1)新建一个MFC的单文档结构应用程序,命名为ToolbarWithMenu。(2)在工程中添加Menu资源,设置ID属性为IDR_MENU1,为菜单添加两个子菜单项。(3)主要程序代码如下:intCMainFrame::OnCreate(LPCREATESTRUCTlpCreateStruct){if(CFrameWnd::OnCreate(lpCreateStruct)==-1)return -1;if (!m_wndToolBar.CreateEx(this,TBSTYLE_FLAT,WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_GRIPPER|CBRS_TOOLTIPS |CBRS_FLYBY|CBRS_SIZE_DYNAMIC) ||!m_wndToolBar.LoadToolBar(IDR_MAINFRAME)){TRACE0("Failedtocreatetoolbar\n");return -1;}if (!m_wndStatusBar.Create(this)||!m_wndStatusBar.SetIndicators(indicators,sizeof(indicators)/sizeof(UINT))){TRACE0("Failedtocreatestatusbar\n");return -1;}m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);EnableDocking(CBRS_ALIGN_ANY);DockControlBar(&m_wndToolBar);m_wndToolBar.GetToolBarCtrl().SetExtendedStyle(TBSTYLE_EX_DRAWDDARROWS); //设置工具栏具有下拉按钮//获得添加下拉按钮的工具栏打开按钮风格DWORDdwStyle=m_wndToolBar.GetButtonStyle(m_wndToolBar.CommandToIndex(ID_FILE_OPEN));dwStyle|=TBSTYLE_DROPDOWN; //添加下拉按钮风格m_wndToolBar.SetButtonStyle(m_wndToolBar.CommandToIndex(ID_FILE_OPEN),dwStyle); //设置下拉按钮风格return 0;}voidCMainFrame::OnToolbarDropdown(NMTOOLBAR*pnmh,LRESULT*plr) //按下下拉按钮{CWnd*pWnd;switch(pnmh->iItem){case ID_FILE_OPEN: //如果是工具栏打开按钮pWnd=&m_wndToolBar; //获得工具栏窗口指针break;default:return;}CMenu menu;menu.LoadMenu(IDR_MENU1); //加载菜单资源CMenu*pPopup=menu.GetSubMenu(0); //获得子菜单ASSERT(pPopup);CRectrc;pWnd->SendMessage(TB_GETRECT,pnmh->iItem,(LPARAM)&rc); //获得区域pWnd->ClientToScreen(&rc); //转换为屏幕坐标系区域pPopup->TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON|TPM_VERTICAL,rc.left,rc.bottom,this,&rc); //显示弹出菜单}voidCMainFrame::OnSubmenu() //菜单项单击时间{AfxMessageBox("你按下的是子菜单"); //弹出消息提示框}voidCMainFrame::OnContextMenu(CWnd* pWnd,CPoint point){CMenu menu;menu.LoadMenu(IDR_LMENU); //加载菜单资源CMenu*pPopup=menu.GetSubMenu(0); //获得子菜单pPopup->TrackPopupMenu(TPM_LEFTALIGN|TPM_LEFTBUTTON,point.x,point.y,this,NULL); //显示弹出菜单}
举一反三
根据本实例,读者可以:
开发右击客户区弹出菜单程序;
实现右击工具栏弹出菜单。实例009 可调整按钮位置的工具栏
本实例可以美化界面、简化操作
实例位置:光盘\mingrisoft\01\09
实例说明
本实例实现了工具栏上两个按钮互换位置的功能。运行程序,选择菜单“查看”/“改变按钮位置”,程序会将“新建”按钮和“保存”按钮进行位置调换。调换前、后的效果分别如图1.10和图1.11所示。图1.10 调换前图1.11 调换后
技术要点
本实例通过 CToolBar 类的 SetButtonInfo 方法实现,SetButtonInfo 方法用来设置工具栏按钮的相关信息,语法如下:
void SetButtonInfo(int nIndex,UINTnID,UINT nStyle,int iImage);
参数说明:
● nIndex:工具栏上按钮的位置。
● nID:工具栏按钮在工程中的资源ID 值。
● nStyle:工具栏按钮的风格。
● iImage:工具栏按钮的图片索引值。
实现过程(1)新建名为ToolbarAjustBtn的单文档MFC工程。(2)修改Menu资源IDR_MAINFRAME,在菜单“查看”下新建子菜单,设置ID属性为ID_VIEW,设置Caption属性为“改变按钮位置”。(3)主要程序代码。
菜单ID_VIEW的实现函数,实现调用MoveButton函数完成工具栏按钮的调整,代码如下:void CMainFrame::OnView(){this->MoveButton(0,2); //调用MoveButton函数调整工具栏按钮位置}
函数MoveButton实现工具栏上不同位置的按钮相互调换,代码如下:void CMainFrame::MoveButton(intoldpos,int newpos){UINTnewID,oldID;newID=m_wndToolBar.GetItemID(newpos); //获得工具栏按钮IDoldID=m_wndToolBar.GetItemID(oldpos); //获得工具栏按钮IDm_wndToolBar.SetButtonInfo(oldpos,newID,0,newpos); //设置工具栏按钮信息m_wndToolBar.SetButtonInfo(newpos,oldID,0,oldpos); //设置工具栏按钮信息}
举一反三
根据本实例,读者可以:
控制工具栏按钮的显示。实例010 动态设置是否显示工具栏按钮文本
本实例可以美化界面、简化操作
实例位置:光盘\mingrisoft\01\010
实例说明
工具栏中的按钮并不一定是都显示按钮文本的,用户可以根据当前的操作随时变化,这样可以提高程序的应用性。本实例根据用户的操作来调整工具栏按钮文本的显示。程序首先创建一个新的工具栏,然后根据数据库中的数据来决定哪个工具栏按钮可以显示。工具栏转换前如图1.12所示,转换后如图1.13所示。图1.12 不显示工具栏按钮文本图1.13 显示工具栏按钮文本
技术要点
本实例中涉及创建工具栏、设置工具栏高度等技术。在程序中可以使用CToolBar来定义一个工具栏对象,通过GetToolBarCtrl方法来获取CToolBarCtrl类对象。通过CToolBarCtrl类对象可以关联图像列表。要设置工具栏按钮高度可以通过SetHeight方法来实现,语法如下:
void SetHeight( int cyHeight );
参数说明:
● cyHeight:要设置的工具栏高度。
实现过程(1)新建一个基于对话框的应用程序。(2)在工程中导入8个图标资源,并向对话框中添加一个按钮控件。(3)在对话框的头文件中声明变量,代码如下:
CToolBar m_ToolBar; //工具栏对象
CimageList m_ImageList; //列表视图对象
BOOL m_bText; //是否显示按钮文本(4)在对话框初始化时创建工具栏,代码如下:BOOLCToolTipDlg::OnInitDialog(){CDialog::OnInitDialog();//…系统代码省略//创建图像列表m_ImageList.Create(16,16,ILC_COLOR24|ILC_MASK,1,1);//向图像列表中添加图标m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON1));m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON2));m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON3));m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON4));m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON5));m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON6));m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON7));m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_ICON8));UINTarray[11];for(int i=0;i<11;i++){if(i==3 ||i==7 ||i==9)array[i]= ID_SEPARATOR;//第4、8、10个按钮为分隔条elsearray[i]=i+1001;}CString str[]={"新建","打开","保存","","剪切","复制","粘贴","","打印","","帮助"};//创建工具栏m_ToolBar.CreateEx(this,TBSTYLE_FLAT,WS_CHILD |WS_VISIBLE|CBRS_TOP|CBRS_GRIPPER |CBRS_TOOLTIPS |CBRS_SIZE_DYNAMIC |CBRS_BORDER_TOP);m_ToolBar.SetButtons(array,11); //设置工具栏按钮for(i=0;i<11;i++){m_ToolBar.SetButtonText(i,str[i]); //设置工具栏按钮文本}m_ToolBar.GetToolBarCtrl().SetImageList(&m_ImageList); //关联图像列表m_ToolBar.SetSizes(CSize(24,24),CSize(16,16)); //设置按钮和图标的大小RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_CONTROLBAR_LAST,0);m_bText = FALSE;returnTRUE;}(5)添加UpdateToolBar函数,该函数用于设置是否显示工具栏按钮文本,代码如下:void CToolTipDlg::UpdateToolBar(BOOLbUpdate){if(bUpdate){m_ToolBar.SetSizes(CSize(32,32),CSize(16,16));//设置按钮和图标的大小m_ToolBar.SetHeight(36); //设置工具栏高度RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_CONTROLBAR_LAST,0);}else{m_ToolBar.SetSizes(CSize(24,24),CSize(16,16));//设置按钮和图标的大小m_ToolBar.SetHeight(28); //设置工具栏高度RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_CONTROLBAR_LAST,0);}}(6)处理“转换”按钮的单击事件,控制工具栏按钮是否显示,代码如下:void CToolTipDlg::OnButtonupdate(){m_bText=!m_bText;UpdateToolBar(m_bText);}
举一反三
根据本实例,读者可以:
根据需要设置工具栏按钮是否可用。实例011 具有提示功能的工具栏
这是一个可以提高分析能力的实例
实例位置:光盘\mingrisoft\01\011
实例说明
在文档/视图结构的应用程序中,默认情况下,当鼠标在工具栏按钮上停留时,会出现一个工具提示条。运行本实例,将鼠标停留在工具栏的某一个按钮上,即可看到该工具按钮的提示信息,效果如图1.14所示。图1.14 具有提示功能的工具栏
技术要点
使工具栏具有提示功能,需要同时具备两个条件。一是工具栏具有CBRS_TOOLTIPS风格,二是工具栏的父窗口需要处理TTN_NEEDTEXT通知消息。在MFC类库中,CFrameWnd默认处理了TTN_NEEDTEXT通知消息,因此,在文档/视图结构的应用程序中,只要工具栏具有CBRS_TOOLTIPS风格,就能够显示提示信息。
如果在对话框中添加TTN_NEEDTEXT通知消息,需要在消息映射部分添加如下代码:
ON_NOTIFY_EX(TTN_NEEDTEXT, 0,OnToolTipNotify)
其中,OnToolTipNotify是处理TTN_NEEDTEXT消息的函数,函数原型如下:
OnToolTipNotify(UINTid,NMHDR *pNMHDR,LRESULT*pResult);
参数说明:
● id:是发送消息的控件ID,但此处没有用,因为控件ID 可以来自于pNMHDR。
● pNMHDR:是一个 NMHDR 结构指针(实际应该是 NMTTDISPINFO 结构指针),NMHDR结构记录了发送消息的控件ID、句柄等信息。
● pResult:表示结果代码指针,TTN_NEEDTEXT 消息可以忽略该参数。
实现过程(1)新建一个基于对话框的应用程序。(2)在对话框类中定义一个CToolBar变量m_wndToolBar。在工作区的资源视图中创建一个工具栏资源,如图1.15所示。图1.15 工具栏资源设计(3)在对话框的OnInitDialog方法中创建工具栏,代码如下://创建工具栏if (!m_wndToolBar.CreateEx(this,TBSTYLE_FLAT,WS_CHILD|WS_VISIBLE|CBRS_TOP|CBRS_GRIPPER|CBRS_TOOLTIPS |CBRS_SIZE_DYNAMIC|CBRS_BORDER_TOP) ||!m_wndToolBar.LoadToolBar(IDR_TOOLBAR1)){TRACE0("Failedtocreatetoolbar\n");return -1; // fail to create}//设置图像和按钮的大小,以适合演示按钮文本m_wndToolBar.GetToolBarCtrl().SetBitmapSize(CSize(16,16)); //设置显示图像大小m_wndToolBar.GetToolBarCtrl().SetButtonSize(CSize(32,32)); //设置工具栏按钮大小//设置按钮文本m_wndToolBar.SetButtonText(0,"新建");m_wndToolBar.SetButtonText(1,"打开");m_wndToolBar.SetButtonText(2,"保存");m_wndToolBar.SetButtonText(4,"剪切");m_wndToolBar.SetButtonText(5,"复制");m_wndToolBar.SetButtonText(6,"粘贴");m_wndToolBar.SetButtonText(8,"打印");m_wndToolBar.SetButtonText(10,"帮助");(4)在对话框的消息映射部分添加TTN_NEEDTEXT消息映射宏。
ON_NOTIFY_EX(TTN_NEEDTEXT, 0,OnToolTipNotify)(5)向对话框中添加OnToolTipNotify方法,代码如下:BOOLCToolHintDlg::OnToolTipNotify(UINTid,NMHDR*pNMHDR, LRESULT*pResult){TOOLTIPTEXT*pTTT=(TOOLTIPTEXT*)pNMHDR;UINTnID=pNMHDR->idFrom; //获取工具栏按钮IDint index=m_wndToolBar.GetToolBarCtrl().CommandToIndex(nID); //根据ID获取按钮索引m_wndToolBar.GetButtonText(index,m_ToolText); //获取按钮文本pTTT->lpszText=m_ToolText.GetBuffer(0); //设置显示的提示信息pTTT->hinst =AfxGetResourceHandle();return(TRUE);}
举一反三
根据本实例,读者可以:
实现具有提示功能的各种控件。
1.4 状态栏应用实例
状态栏位于主界面的底部,通常用于显示系统时间、程序运行时当前的状态信息等。在MFC中,提供了CStatusBar类用于创建和管理状态栏。本节将通过几个实例介绍状态栏的设计。实例012 动画效果的状态栏
这是一个可以提高基础技能的实例
实例位置:光盘\mingrisoft\01\012
实例说明
在许多媒体软件中,状态栏中会播放一个动画,使界面更加美观。本实例就实现了一个动画效果的状态栏,效果如图1.16所示。图1.16 动画效果的状态栏
技术要点
使状态栏播放一个动画很容易,只要将CAnimateCtrl控件放置在状态栏中就可以了。因为CAnimateCtrl控件可以播放无声的AVI动画。
实现过程(1)新建一个基于对话框的应用程序。(2)在对话框中放置CAnimateCtrl控件,并通过类向导将其命名为m_Animate。(3)在对话框类中定义一个CStatusBar变量m_StatusBar。(4)在对话框的OnInitDialog方法中创建状态栏,并将CAnimateCtrl控件显示在状态栏中。代码如下:m_StatusBar.Create(this); //创建状态栏UINT Indicates[4];for (int i =0; i<4;i++){Indicates[i]=50+i; //为数组元素赋值}m_StatusBar.SetIndicators(Indicates,4); //设置面板IDm_StatusBar.GetStatusBarCtrl().SetMinHeight(30); //设置面板高度CRect rect;GetClientRect(rect); //获得窗体客户区域UINTPaneWidth= rect.Width()/5; //计算面板宽度for(int n =0;n<4;n++){m_StatusBar.SetPaneInfo(n,50+n*10,SBPS_NORMAL,PaneWidth); //设置面板宽度}//设置状态栏面板文本m_StatusBar.SetPaneText(0,"用户名称");m_StatusBar.SetPaneText(1,"明日科技");m_StatusBar.SetPaneText(2,"动画");m_Animate.SetParent(&m_StatusBar); //设置动画控件的父窗口为状态栏//显示状态栏RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_CONTROLBAR_LAST,0);CRect Rect;m_StatusBar.GetStatusBarCtrl().GetRect(3,&Rect); //获得面板区域CRectProgRect(Rect.left,2,Rect.right,Rect.Height()+2); //设置显示位置m_Animate.MoveWindow(ProgRect); //移动动画控件位置m_Animate.Open("dmt.avi"); //打开AVI文件m_Animate.Play(0,-1,-1); //播放AVI文件
举一反三
根据本实例,读者可以:
设计播放FLASH动画的状态栏。实例013 滚动字幕的状态栏
这是一个可以启发思维的实例
实例位置:光盘\mingrisoft\01\013
实例说明
在火车站、客运站等许多公共场所,随处可以看见一个大屏幕,上面经常会以滚动字幕的形式显示一些信息。本实例实现了一个滚动字幕的状态栏,效果如图1.17所示。图1.17 滚动字幕的状态栏
技术要点
在状态栏中实现滚动字幕,可以利用静态文本控件实现。在状态栏中显示一个静态文本控件,然后每隔一段时间调整静态文本控件的位置,即可实现滚动字幕的效果了。
实现过程(1)新建一个基于对话框的应用程序。(2)在对话框中放置两个静态文本控件,通过属性窗口设置控件的ID和Caption属性。(3)通过类向导将两个静态文本控件分别命名为m_Parent和m_Web。(4)在对话框类的OnInitDialog方法中创建状态栏,将静态文本控件显示在状态栏中,代码如下:
m_StatusBar.Create(this); //创建状态栏UINT Indicates[4];for (int i =0; i<4;i++){Indicates[i]=50+i; //为数组元素赋值}m_StatusBar.SetIndicators(Indicates,4); //设置面板IDCRect rect;GetClientRect(rect); //获得控件的客户区域UINTPaneWidth= rect.Width()/6; //计算面板宽度//设置面板宽度for(int n =0;n<3;n++){m_StatusBar.SetPaneInfo(n,50+n*10,SBPS_NORMAL,PaneWidth); //设置面板宽度}//设置状态栏面板文本m_StatusBar.SetPaneInfo(3,111,SBPS_NORMAL,800);m_StatusBar.SetPaneText(0,"用户名称");m_StatusBar.SetPaneText(1,"明日科技");m_StatusBar.SetPaneText(2,"网址");RepositionBars(AFX_IDW_CONTROLBAR_FIRST,AFX_IDW_CONTROLBAR_LAST,0);//显示状态栏//设置静态文本控件的父窗口为状态栏m_Parent.SetParent(&m_StatusBar);m_StatusBar.GetStatusBarCtrl().GetRect(3,Rect); //获取控件的显示区域Rect.DeflateRect(1,1,1,1); //设置区域m_Parent.MoveWindow(Rect); //移动控件位置m_Parent.GetClientRect(Rect); //获得控件的客户区域m_Web.GetClientRect(rect1); //获得控件的客户区域m_Web.SetParent(&m_Parent); //设置控件的父窗口m_Parent.GetClientRect(CurRect); //获得控件的客户区域CurRect.DeflateRect(0,1,Rect.Width()-rect1.Width(),1); /设置控件要移动到的区域m_Web.MoveWindow(CurRect); //移动控件SetTimer(1,200,NULL); //设置定时器(5)处理对话框的WM_TIMER消息,代码如下:void CScrollStatusDlg::OnTimer(UINTnIDEvent){if (CurRect.left>=Rect.right) //如果移动区域左边大于等于面板右边界{CurRect.left=Rect.left-rect1.Width(); //设置移动区域左边界CurRect.right=Rect.left; //设置移动区域右边界}else //否则{CurRect.left+=4; //设置移动区域左边界+4CurRect.right+=4; //设置移动区域右边界+4}//调整控件位置m_Web.MoveWindow(CurRect);}
举一反三
根据本实例,读者可以:
设计滚动字幕的工具栏。
1.5 导航界面应用实例
如今的应用软件不但具有丰富的功能,还应具有人性化的界面,这样,才能吸引用户。本节主要介绍几种常用的导航界面。实例014 Outlook导航界面
本实例可以方便操作、提高效率
实例位置:光盘\mingrisoft\01\014
实例说明
采用导航式功能菜单,不但美观大方,而且为用户操作程序提供了方便。下面介绍Outlook导航界面式菜单的设计方法。运行程序,Outlook式导航界面的效果如图1.18所示。图1.18 Outlook 导航界面
技术要点
为了设计Outlook导航界面,需要从CListCtrl派生一个子类,本实例为COutlookList。在该类中显示一些导航按钮。当用户单击这些按钮时,会适当调整按钮的位置,并在客户区域(除按钮占用区域之外的区域)显示另一个CListCtrl控件,本实例为m_ClientList,目的是显示与导航按钮关联的项目。在设计COutlookList类时,需要解决几个关键问题:一是如何截获导航按钮的单击事件,并确定用户单击了哪个按钮;二是如何存储与导航按钮关联的项目;三是如何向外界提供一个接口,以方便处理用户双击视图项执行的动作。
对于问题一,可以在COutlookList的OnCmdMsg方法中实现,代码如下:BOOLCOutlookList::OnCmdMsg(UINTnID,intnCode,void* pExtra,AFX_CMDHANDLERINFO*pHandlerInfo){intindex=CommandToIndex(nID);if (index!=-1){OnButtonDown(index,nID);}m_ClientList.OnCmdMsg(nID,nCode,pExtra,pHandlerInfo);return CListCtrl::OnCmdMsg(nID,nCode,pExtra,pHandlerInfo);}
在OnCmdMsg方法中首先调用自定义的CommandToIndex方法获取命令对应的按钮索引,因为在创建导航按钮时,会为按钮指定ID,并将按钮存储在m_pButton按钮数组中,只要遍历m_pButton,就可以根据按钮ID确定索引了。如果导航按钮索引不为−1,表示用户单击了导航按钮,执行自定义的OnButtonDown方法,重新排列按钮,在客户区域显示列表控件。
对于问题二,可以从 CButton 派生一个子类(本实例为 CListButton),在该类中定义一个字符串列表m_ButtonItems(类型为CStringList),存储与导航按钮关联的项目文本。
对于问题三,可以定义一个回调函数,本实例为ItemDlbFun,代码如下:
//定义双击列表视图项的回调函数
typedef void(ItemDlbFun)(const CListCtrl* pListCtrl,int nItemIndex);
然后在 COutlookList 类中定义一个 ItemDlbFun 函数指针 pItemDlbFun。最后在 COutlookList类的PreTranslateMessage方法中判断用户是否双击了视图项,如果是,则调用pItemDlbFun。BOOL COutlookList::PreTranslateMessage(MSG* pMsg){if((pMsg->hwnd==m_ClientList.m_hWnd)&&(pMsg->message==WM_LBUTTONDBLCLK)){intindex;index=m_ClientList.GetSelectionMark(); //获取用户双击的项目if (pItemDlbFun!=NULL)pItemDlbFun(&m_ClientList,index);}return CListCtrl::PreTranslateMessage(pMsg);}
实现过程(1)新建一个基于对话框的应用程序。(2)在对话框中添加列表视图控件和图片控件。设置图片控件属性如图1.19所示。图1.19 图片控件属性设置(3)从CListCtrl类派生一个子类COutlookList,在该类中定义如下成员变量:
CPtrArraym_pButton; //按钮数组
UINTm_ButtonCount ; //按钮数量
UINTm_LeftMargin; //图像列表显示的左边距
CListCtrlm_ClientList; //在客户区域显示视图项
ItemDlbFun*pItemDlbFun; //视图项的双击事件(4)从CButton类派生一个子类CListButton,作为导航按钮。(5)在CListButton中定义如下成员变量:
UINTm_Index; //导航按钮索引
BOOLm_Toped; //按钮是否在列表上方
CStringListm_ButtonItems; //按钮关联的图像列表项(6)在COutlookList中添加AddButton方法,用于添加导航按钮,代码如下:void COutlookList::AddButton(LPCSTRBtntext,UINTuID){int index=m_pButton.Add(newCListButton);//创建按钮控件((CListButton*)m_pButton[m_pButton.GetSize()-1])->Create(Btntext,WS_CHILD,GetAddButtonRect(),this,uID);((CListButton*)m_pButton[m_pButton.GetSize()-1])->m_Index= index; //设置按钮索引((CListButton*)m_pButton[m_pButton.GetSize()-1])->ShowWindow(SW_SHOW); //显示控件m_ButtonCount+=1; //统计按钮数量}(7)在COutlookList中添加AddButtonItems方法,用于设置导航按钮关联的项目,代码如下:void COutlookList::AddButtonItems(UINT nIndex,CString & strItem){CListButton*temp;temp= (CListButton*)m_pButton[nIndex]; //获得按钮指针temp->m_ButtonItems.AddTail(strItem); //记录列表项}(8)在COutlookList中添加ShowButtonItems方法,用于显示指定导航按钮关联的项目,代码如下:void COutlookList::ShowButtonItems(UINTnIndex){CListButton*temp;temp= (CListButton*)m_pButton[nIndex]; //获取指定的导航按钮m_ClientList.DeleteAllItems(); //清空列表控件CRect showrect=GetListClientRect(); //获取客户区域if (temp->m_ButtonItems.GetCount()>0){POSITIONpos;pos= temp->m_ButtonItems.GetHeadPosition(); //列表项索引CString str= temp->m_ButtonItems.GetHead(); //获得列表项文本CRect ClientRect;ClientRect=GetListClientRect(); //获得列表区域intm=0;m_ClientList.InsertItem(m,str,m); //插入列表项m_ClientList.SetItemPosition(m,CPoint(m_LeftMargin,20+m*48)); //设置列表项位置while (pos!= temp->m_ButtonItems.GetTailPosition()){str= temp->m_ButtonItems.GetNext(pos); //获得下一个列表项文本m_ClientList.InsertItem(m,str,m); //插入列表项m_ClientList.SetItemPosition(m,CPoint(m_LeftMargin,20+m*48)); //设置列表项位置m+=1;}str= temp->m_ButtonItems.GetAt(pos); //获得文本m_ClientList.InsertItem(m,str,m); //插入列表项m_ClientList.SetItemPosition(m,CPoint(m_LeftMargin,20+m*48)); //设置列表项位置}}
举一反三
根据本实例,读者可以:
利用TreeControl控件制作导航界面。实例015 树状导航界面
本实例可以美化界面、简化操作
实例位置:光盘\mingrisoft\01\015
实例说明
树状导航界面很常见,系统中资源浏览器的左边就是一个树状的导航界面。本实例利用两层树型视图来实现树状导航界面,用户可以通过双击树型视图的单个项实现某些功能,如图1.20所示。图1.20 树状导航界面
技术要点
本实例通过窗体的分割技术将树型视图显示在左边,然后通过树型视图的 GetTreeCtrl 方法来获得 CTreeCtrl 对象,通过CTreeCtrl对象接受双击事件来实现导航功能。
实现过程(1)新建名为TreeNavi的单文档应用程序。(2)在工程中添加以 CTreeView 类为基类的新类TreeView;在工程中添加Icon资源。(3)在TreeView.h文件中添加如下代码:
#include"afxcview.h"(4)修改TreeNavi.cpp文件中InitInstance函数的内容,代码如下:BOOL CTreeNaviApp::InitInstance(){…//此处代码省略CSingleDocTemplate* pDocTemplate;pDocTemplate =new CSingleDocTemplate(IDR_MAINFRAME,RUNTIME_CLASS(CTreeNaviDoc),RUNTIME_CLASS(CMainFrame),//去除原有的TreeNaviView视图的应用// RUNTIME_CLASS(CTreeNaviView)NULL);AddDoc Template(pDocTemplate);…//此处代码省略return TRUE;}(5)在MainFrm.cpp文件中添加WM_CREATECLIENT消息的实现函数,实现分割窗体,代码如下:BOOLCMainFrame::OnCreateClient(LPCREATESTRUCTlpcs, CCreateContext* pContext){split.CreateStatic(this,1,2); //创建分割窗体split.CreateView(0,0,RUNTIME_CLASS(TreeView),CSize(100,100),pContext); //创建左侧子视图split.CreateView(0,1,RUNTIME_CLASS(CTreeNaviView),CSize(100,100),pContext); //创建右侧子视图return CFrameWnd::OnCreateClient(lpcs,pContext);}(6)函数OnInitialUpdate实现树型视图的初始化,代码如下:voidTreeView::OnInitialUpdate(){CTreeView::OnInitialUpdate();list.Create(32,32,ILC_COLOR32|ILC_MASK,0,0); //创建图像列表list.Add(::AfxGetApp()->LoadIcon(IDI_ICON1)); //加载图标资源…//此处代码省略this->GetTreeCtrl().SetImageList(&list,TVSIL_NORMAL); //关联图像列表HTREEITEM tree;//创建树状结构tree=this->GetTreeCtrl().InsertItem("导航1",0,1);this->GetTreeCtrl().InsertItem("子导航1",6,6,tree);this->GetTreeCtrl().InsertItem("子导航2",7,7,tree);this->GetTreeCtrl().InsertItem("子导航3",8,8,tree);tree=this->GetTreeCtrl().InsertItem("导航2",2,3);this->GetTreeCtrl().InsertItem("子导航4",9,19,tree);this->GetTreeCtrl().InsertItem("子导航5",10,10,tree);this->GetTreeCtrl().InsertItem("子导航6",11,11,tree);tree=this->GetTreeCtrl().InsertItem("导航3",4,5);this->GetTreeCtrl().InsertItem("子导航7",12,12,tree);this->GetTreeCtrl().InsertItem("子导航8",13,13,tree);this->GetTreeCtrl().InsertItem("子导航9",14,14,tree);}(7)添加NM_DBLCLK消息的实现函数OnDblclk,代码如下:void TreeView::OnDblclk(NMHDR* pNMHDR,LRESULT* pResult){HTREEITEM tree=this->GetTreeCtrl().GetSelectedItem();if(!this->GetTreeCtrl().GetChildItem(tree)){CString str=this->GetTreeCtrl().GetItemText(tree); //获得树节点文本AfxMessageBox(str); //弹出消息提示}*pResult =0;}
举一反三
根据本实例,读者可以:
实现列表视图导航。实例016 按钮导航界面
本实例可以美化界面、简化操作
实例位置:光盘\mingrisoft\01\016
实例说明
一般应用程序都使用菜单作为导航,用户通过操作菜单来实现某些功能。本实例使用多个按钮来作为用户操作的引导,效果如图1.21所示。图1.21 按钮导航界面
技术要点
为了使界面漂亮,本实例以 CButton 类为基类派生一个子类CCustomButton,然后声明一个枚举变量,用于设置按钮控件的 3种状态,分别是正常状态、热点状态、按下状态,在CCustomButton类的 WM_MOUSEMOVE 事件中设置按钮是否为热点状态,在WM_LBUTTONDOWN事件和WM_LBUTTONUP事件中设置按钮的按下和正常状态,最后在CCustomButton类的OnPaint方法中绘制按钮,这样就使程序界面看起来更加美观了。
实现过程(1)新建一个基于对话框的应用程序。(2)向对话框中添加两个按钮控件。(3)以 CButton 类为基类派生一个按钮类 CCustomButton,并为两个按钮控件分别关联一个CCustomButton类的变量。(4)定义一个枚举类型,代码如下:
enum ButtonState {bsNormal,bsHot,bsDown}; //正常状态,热点状态、按下状态(5)在CCustomButton类的头文件中声明变量,代码如下:
int m_State; //按钮当前状态(6)在CCustomButton类的构造函数和析构函数中设置按钮的状态,代码如下:CCustomButton::CCustomButton() //构造函数{m_State = bsNormal; //设置为默认状态}CCustomButton::~CCustomButton() //析构函数{m_State = bsNormal; //设置为默认状态}(7)在CCustomButton类中,处理按钮的WM_MOUSEMOVE事件,在该事件的处理函数中设置按钮是否为热点状态,代码如下:void CCustomButton::OnMouseMove(UINTnFlags,CPoint point){HRGNhRgn=CreateRectRgn(0,0,0,0);GetWindowRgn(hRgn); //获得按钮区域BOOL ret=PtInRegion(hRgn,point.x,point.y); //鼠标是否在按钮上if(ret) //在按钮上{if(m_State==bsDown) //判断按钮是否为按下状态return ;if(m_State!=bsHot) //判断按钮是否为热点状态{m_State=bsHot; //设置为热点状态InvalidateRect(NULL,TRUE); //更新按钮SetCapture(); //捕获鼠标}}else //不在按钮上{m_State=bsNormal; //设置按钮状态InvalidateRect(NULL,TRUE); //更新按钮ReleaseCapture(); //释放鼠标}DeleteObject( hRgn );CButton::OnMouseMove(nFlags, point);}(8)在 CCustomButton 类中,处理按钮的 WM_LBUTTONDOWN 事件,在该事件的处理函数中设置按钮为按下状态,代码如下:void CCustomButton::OnLButtonDown(UINTnFlags,CPoint point){m_State=bsDown; //设置按钮按下状态InvalidateRect(NULL,TRUE); //更新按钮}(9)在CCustomButton类中,处理按钮的WM_LBUTTONUP事件,在该事件的处理函数中设置按钮为默认状态,代码如下:void CCustomButton::OnLButtonUp(UINTnFlags,CPoint point){if(m_State!=bsNormal) //判断按钮状态{m_State=bsNormal; //设置按钮状态ReleaseCapture(); //释放鼠标捕捉InvalidateRect(NULL,TRUE); //更新按钮}//向父窗口发送命令消息::SendMessage(GetParent()->m_hWnd,WM_COMMAND, GetDlgCtrlID(),(LPARAM) m_hWnd);}(10)在CCustomButton类中,处理按钮的WM_PAINT事件,在该事件的处理函数中根据按钮的状态绘制按钮控件,代码如下:void CCustomButton::OnPaint(){CPaintDCdc(this); //获取按钮的设备上下文CString Text; //定义一个字符串变量CRect RC; //定义一个区域对象CFont Font; //定义一个字体对象CFont *pOldFont; //定义一个字体对象指针,用于存储之前的字体CBrush Brush; //定义一个画刷对象CBrush *pOldBrush; //定义一个画刷对象指针,用于存储之前的画刷对象CPoint PT(2,2); //定义一个点对象dc.SetBkMode(TRANSPARENT); //将设备上下文背景模式设置为透明Font.CreateFont(12,0,0,0,FW_HEAVY, 0,0,0,ANSI_CHARSET,OUT_TT_PRECIS,CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY,VARIABLE_PITCH |FF_SWISS, "宋体"); //创建字体pOldFont=dc.SelectObject(&Font); //选中新的字体if(m_State== bsNormal) //判断按钮是否为正常状态{Brush.CreateSolidBrush(RGB(230,230,230)); //创建指定颜色的画刷dc.SetTextColor(RGB(0, 0, 0)); //设置文本颜色}else if(m_State==bsDown) //判断按钮是否为按下状态{Brush.CreateSolidBrush(RGB(100,100,180)); //创建指定颜色的画刷dc.SetTextColor(RGB(250,250,0)); //设置文本颜色}else if(m_State==bsHot) //判断按钮是否为热点状态{Brush.CreateSolidBrush(RGB(230,230,130)); //创建指定颜色的画刷dc.SetTextColor(RGB(50,50,250)); //设置文本颜色}pOldBrush=dc.SelectObject(&Brush); //选中画刷GetClientRect(&RC); //获取按钮的客户区域dc.RoundRect(&RC,PT); //利用当前选中的画刷和画笔绘制按钮区域HRGNhRgn=CreateRectRgn(RC.left,RC.top,RC.right,RC.bottom); //创建一个选区SetWindowRgn(hRgn,TRUE); //设置按钮窗口区域DeleteObject(hRgn); //删除选区GetWindowText(Text); //获取按钮文本dc.DrawText(Text,&RC,DT_CENTER |DT_VCENTER |DT_SINGLELINE); //绘制按钮文本Font.DeleteObject(); //删除字体对象Brush.DeleteObject(); //删除画刷对象dc.SelectObject(pOldFont); //恢复原来选中的字体dc.SelectObject(pOldBrush); //恢复原来选中的画刷}
举一反三
根据本实例,读者可以:
在视图中利用按钮导航。实例017 图片导航界面
本实例可以美化界面、简化操作
实例位置:光盘\mingrisoft\01\017
实例说明
本实例实现了图片导航界面。程序中的每个按钮中都有一个图片,当用户的鼠标在图片上滑过时,按钮显示热点效果的图片,使用户清楚地知道当前执行的操作,通过单击不同的图片可以实现相应的功能。程序运行效果如图1.22所示。图1.22 图片导航界面
技术要点
要实现本实例的主要功能,主要通过按钮控件的显示和隐藏。首先设置按钮控件全部隐藏,然后在鼠标滑过当前按钮控件时,为按钮控件设置为显示图片,并显示当前的按钮控件,从而达到控件的热点效果。
实现过程(1)新建名为Navigation的对话框应用程序。(2)在工程中添加5个位图文件,并添加一个图片控件和4个按钮控件,设置按钮控件的Bitmap属性和Flat属性,设置图片控件显示背景位图。(3)OnInitDialog函数中设置按钮控件隐藏,代码如下:BOOL CNavigationDlg::OnInitDialog(){CDialog::OnInitDialog();//系统代码省略//隐藏按钮控件GetDlgItem(IDC_BUTTON1)->ShowWindow(SW_HIDE);GetDlgItem(IDC_BUTTON2)->ShowWindow(SW_HIDE);GetDlgItem(IDC_BUTTON3)->ShowWindow(SW_HIDE);GetDlgItem(IDC_BUTTON4)->ShowWindow(SW_HIDE);return TRUE;}(4)处理主窗体的WM_MOUSEMOVE消息,在该消息的处理函数中设置按钮的显示图片,并显示指定按钮控件,代码如下:void CNavigationDlg::OnMouseMove(UINTnFlags,CPoint point){intx=point.x;int y= point.y;if (x>=27 && y>=141&&x<=56&&y<=171) //判断鼠标是否在基本信息按钮范围内{HBITMAPhbmp;hbmp= (HBITMAP)::LoadImage(AfxFindResourceHandle(MAKEINTRESOURCE(IDB_BITMAP1),RT_GROUP_ICON),MAKEINTRESOURCE(IDB_BITMAP1), IMAGE_BITMAP,0,0,0);//加载图片资源CButton*p= (CButton*)GetDlgItem(IDC_BUTTON1); //获得按钮指针p->ShowWindow(SW_SHOW); //显示控件p->SetFocus(); //按钮控件获得焦点p->SetBitmap(hbmp); //显示图片}else if(x>=27&&y>=192&&x<=56&&y<=220) //判断鼠标是否在库存管理按钮范围内{HBITMAPhbmp;hbmp= (HBITMAP)::LoadImage(AfxFindResourceHandle(MAKEINTRESOURCE(IDB_BITMAP2),RT_GROUP_ICON),MAKEINTRESOURCE(IDB_BITMAP2), IMAGE_BITMAP,0,0,0);//加载图片资源CButton*p= (CButton*)GetDlgItem(IDC_BUTTON2); //获得按钮指针p->ShowWindow(SW_SHOW); //显示控件p->SetBitmap(hbmp); //显示图片}else if(x>=27&&y>=245&&x<=56&&y<=266) //判断鼠标是否在查询管理按钮范围内{HBITMAPhbmp;hbmp= (HBITMAP)::LoadImage(AfxFindResourceHandle(MAKEINTRESOURCE(IDB_BITMAP3),RT_GROUP_ICON),MAKEINTRESOURCE(IDB_BITMAP3), IMAGE_BITMAP,0,0,0);//加载图片资源CButton*p= (CButton*)GetDlgItem(IDC_BUTTON3); //获得按钮指针p->ShowWindow(SW_SHOW); //显示控件p->SetBitmap(hbmp); //显示图片}else if(x>=27&&y>=289&&x<=56&&y<=318) //判断鼠标是否在系统设置按钮范围内{HBITMAPhbmp;hbmp= (HBITMAP)::LoadImage(AfxFindResourceHandle(MAKEINTRESOURCE(IDB_BITMAP4),RT_GROUP_ICON),MAKEINTRESOURCE(IDB_BITMAP4), IMAGE_BITMAP,0,0,0);//加载图片资源CButton*p= (CButton*)GetDlgItem(IDC_BUTTON4); //获得按钮指针p->ShowWindow(SW_SHOW); //显示控件p->SetBitmap(hbmp); //显示图片}else{//隐藏按钮控件GetDlgItem(IDC_BUTTON1)->ShowWindow(SW_HIDE);GetDlgItem(IDC_BUTTON2)->ShowWindow(SW_HIDE);GetDlgItem(IDC_BUTTON3)->ShowWindow(SW_HIDE);GetDlgItem(IDC_BUTTON4)->ShowWindow(SW_HIDE);}CDialog::OnMouseMove(nFlags, point);}
举一反三
根据本实例,读者可以:
开发图标导航界面。
试读结束[说明:试读内容隐藏了图片]