定制应用程序外观.doc_第1页
定制应用程序外观.doc_第2页
定制应用程序外观.doc_第3页
定制应用程序外观.doc_第4页
定制应用程序外观.doc_第5页
已阅读5页,还剩24页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

修改应用程序窗口的外观:道理如同盖楼一样,在盖楼之前要设计好外观,大小等.我们做MFC的程序也应该这样.在窗口创建之前修改:首先新建一个单文档类型的MFC AppWizard(exe)工程,取名为Style.如果希望在应用程序创建之前修改它的外观和大小,就应该在CMainFrame类的PreCreateWindow成员函数中进行.该函数是一个虚函数.在MFC底层代码中,当调用该函数时,如果传递了子类对象的指针,根据多态性原理,那么就会调用子类对象的PreCreateWindow函数.这个函数有一个参数,类型是CREATETRUCT结构,它的结构中的字段与CreateWindowEx函数的参数完全一致,只是先后顺序相反而已.另外PreCreateWindow函数的这个参数声明为引用类型.如果在子类对象中修改了参数中成员变量的值,那么这种改变会反映到MFC底层代码中,当MFC底层代码调用CreateWindowEx函数去创建窗口时,它就会使用改变后的参数值去创建这个窗口.因此,为了修改一个窗口的外观和大小,我们只需要修改CREATETRUCT结构体中的相关成员变量的值就可以了.我们修改程序窗口大小,宽度为300,高度为200;BOOL CMainFrame:PreCreateWindow(CREATESTRUCT& cs) if( !CFrameWnd:PreCreateWindow(cs) ) return FALSE; / TODO: Modify the Window class or styles here by modifying / the CREATESTRUCT cs cs.cx =300; cs.cy = 200; return TRUE; 如果想要修改窗口的标题,可以通过CREATETRUCT结构体中的lpszName成员的值来实现.可以加入cs.lpszName = sw的实验程序,在cs.cy=.之后.编译运行之后,并不能得到预期效果.当我们新建一个Word文档时,Word窗口标题栏上显示的标题是”文档1”,当我们再新建一个Word文档时,它的标题变为”文档2”;当继续新建文档,它们会变为”文档3,文档4.”同样,在MFC SDI应用程序窗口标题栏上显示的”无标题”这个字符串也是文档的标题.我们创建的这个Style应用程序是一个SDI应用程序,在单文档界面(SDI)应用程序中,框架的默认窗口样式是WS_OVERLAPPEDWINDOW和FWS_ADDTOTITLE样式的组合.其中FWS_ADDTOTITLE是MFC特定的一种样式,指示框架将文档标题添加到窗口标题上.因此,如果想要显示自己设置的标题,只需将窗口的FWS_ADDTOTITLE样式去掉.去掉某个类型的方法就是对FWS_ADDTOTITLE类型取反,并与现在窗口类型进行与操作:cs.style &= FWS_ADDTOTITLE;或者cs.style =cs.style &- FWS_ADDTOTITLE; 加在设置窗口标题代码前面;BOOL CMainFrame:PreCreateWindow(CREATESTRUCT& cs) if( !CFrameWnd:PreCreateWindow(cs) ) return FALSE; / TODO: Modify the Window class or styles here by modifying / the CREATESTRUCT cs cs.cx =300; cs.cy = 200; cs.style =cs.style & FWS_ADDTOTITLE; cs.lpszName = sw的实验程序; return TRUE; 编译运行,可以得到我们期待的结果,以上修改同样可以是直接把CREATETRUCT结构体的style成员设置为WS_OVERLAPPEDWINDOW,该成员初始值为cs.style =WS_OVERLAPPEDWINDOW | FWS_ADDTOTITLE;可以将该成员改为:cs.style =WS_OVERLAPPEDWINDOW.效果相同 在窗口创建之后修改: 窗口创建之后,可以使用SetWindowLong这个函数来实现窗口的修改.为了改变窗口的类型,该函数的第二个参数应指定为GWL_STYLE,第三个参数应指定新的窗口类型.在MFC程序中,如果想在窗口创建之后修改其外观,可以在框架类CMainFrame的OnCreate函数中添加实现代码.它是通过调用基类的OnCreate函数来完成窗口的创建.我们将上个例子中加入的代码注释掉. int CMainFrame:OnCreate(LPCREATESTRUCT lpCreateStruct). / TODO: Delete these three lines if you dont want the toolbar to / be dockable m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); SetWindowLong(m_hWnd,GWL_STYLE,WS_OVERLAPPEDWINDOW); return 0; 编译运行,发现应用程序窗口标题栏上去掉了文档的标题.当修改窗口外观时,如果在已有类型的基础上进行一些修改的话,那么首先要获得这个窗口的现有类型,这可以利用GetWindowLong这个函数来实现.该函数作用是获取指定窗口的消息.LONG GetWindowLong(HWND hWnd,int nIndex) 其中,第一个参数是想要获取心想的窗口句柄,第二个参数是指定要获得的消息类型.这个函数如同GetWindowLong函数,如果设定为GWL_STYLE,那么该函数就获取指定窗口的类型.GetWindowLong函数的返回值就是获取到的窗口信息. 知识点:GWL就是GetWindowLong三个单词首字母的缩写.下面在CMainFrame类的OnCreate函数中,加入修改外观的语句.利用GetWindowLong函数和SetWindowLng函数来修改Style程序窗口外观:去掉窗口的最大化功能: SetWindowLong(m_hWnd,GWL_STYLE,GetWindowLong(m_hWnd,GWL_STYLE)& WS_MAXIMIZEBOX);加入OnCreate函数的return之前. 修改窗口的光标,图标和背景: 在窗口创建之前修改: 窗口的类型和大小,是在创建窗口时设定的,而光标,图标和背景是在设计窗口类时指定的,窗口类的设计和注册是由MFC底层代码自动帮助我们完成的.因此我们不能修改MFC底层代码,但是我们可以编写自己的窗口类并注册,然后让随后的窗口按照我们编写的窗口类去创建.我们在Style程序的CMainFrame类的PreCreateWindow函数中编写一个自己的窗口类并注册. BOOL CMainFrame:PreCreateWindow(CREATESTRUCT& cs) if( !CFrameWnd:PreCreateWindow(cs) ) return FALSE; / TODO: Modify the Window class or styles here by modifying / the CREATESTRUCT cs WNDCLASS wndcls; wndcls.cbClsExtra=0; wndcls.cbWndExtra=0; wndcls.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH); wndcls.hCursor=LoadCursor(NULL,IDC_HELP); wndcls.hIcon=LoadIcon(NULL,IDI_ERROR); wndcls.hInstance=AfxGetInstanceHandle(); wndcls.lpfnWndProc=:DefWindowProc; wndcls.lpszClassName=sw; wndcls.lpszMenuName=NULL; wndcls.style=CS_HREDRAW | CS_VREDRAW; RegisterClass(&wndcls); cs.lpszClass =sw; 首先定义一下WNDCLASS类型的变量wndcls,然后设置该变量的各个成员:类的额外内存cbClsExtra和窗口的额外内存cbWndExtra:这里不需要使用它们,所以设置为0窗口背景:利用GetStockObject函数获得一个黑色的画刷来设置窗口类的背景(hbrBackground),该函数返回的是HGDIOBJ类型,而这里需要的是一个画刷句柄(HBRUSH)所以要进行强制转换.窗口的光标(hCursor):使用LoadCursor函数加载一个光标.如果使用系统标准光标,则该函数的第一个参数必须设置为NULL,第二个参数就是标准光标的ID,系统提供的帮助光标为IDC_HELP;窗口的图标(hIcon):童谣使用LoadIcon函数加载,第一个为NULL,表示使用系统标准图标,第二个参数是标准图标的ID应用程序实例的句柄(hInstance):获取当前应用程序的句柄,可以使用全局函数AfxGetInstanceHandle,来获得当前应用程序的实例句柄.提示:凡是以Afx开始的函数都是应用程序框架类函数,也就是全局函数,在程序的所有类中可以直接调用.窗口过程(lpfnWndProc):本例只想改光标,图标,背景,并不想改变它的窗口过程,也不想对消息进行一些特殊处理,所以直接调用DefWindowProc函数获得窗口的过程.因为CWnd类中也有一个DefWindowProc成员函数,这里应该调用相应的全局API函数.因此在前面加上:.类的名称”lpszClassName”:设定为”sw”菜单的名称(lpszMenuName):设置为Null.窗口的菜单并不是在设计窗口类时创建的,当利用AppWizard生成MFC SDI应用程序时,在应用程序类(即本类CStyleApp类)的InitIstance函数中CSingleDocTemplate* pDocTemplate; pDocTemplate = new CSingleDocTemplate( IDR_MAINFRAME, RUNTIME_CLASS(CStyleDoc), RUNTIME_CLASS(CMainFrame), / main SDI frame window RUNTIME_CLASS(CStyleView); AddDocTemplate(pDocTemplate); 也就是说,创建单文档模板时,将菜单资源表示IDR_MAINFRAME作为其中的一个参数传入.当MFC底层代码在创建框架窗口时,就会把表示转换为相应的菜单句柄,然后去创建菜单和框架窗口.因此这里要设置为null,并不会影响窗口菜单创建. 类型Style:这里并不是窗口的类型,而是窗口类的类型.本例指定窗口类具有水平重绘和垂直重绘这两种类型.设计完窗口类,就应该注册这个窗口类,这样我们就有了一个新的窗口类.它的光标,图标和背景都是我们设计的.接下来的工作,就是让程序框架窗口类按照我们设计的窗口类来创建,也就是将当前窗口的类名(cs的lpszClass成员)改为”sw”. 编译运行,窗口背景还是白色,光标仍然是默认的光标,但是程序的图标发生了变化.应用程序包含有两个窗口:应用程序框架窗口和视类窗口,前者包含了后者,后者覆盖在前者的上面.当Style程序运行后,我们看到的窗口实际上是视类窗口,然而我们修改的实际上是框架窗口的背景和光标.同时,应用程序的图标属于框架窗口.因此,上述Style程序运行后,程序窗口左上角的图标发生了改变.也就是说,在应用程序框架类中只能改变程序窗口的图标,而如果想要改变应用程序窗口的背景和光标的话,只能在视类中实现.因此对Style程序来说,我们应该在其视类(CStyleView)创建窗口之前,即在PreCreateWindow函数. BOOL CStyleView:PreCreateWindow(CREATESTRUCT& cs) / TODO: Modify the Window class or styles here by modifying / the CREATESTRUCT cs cs.lpszClass =sw; return CView:PreCreateWindow(cs); 编译运行,OK,没有问题. 综合上边这些实验:在MFC程序中,如果想要修改应用程序窗口的图标,则应在框架类中进行,因为在框架窗口中才有标题栏,所以才能修改位于改标题栏上的图标.如果想要修改程序窗口的背景和光标,就应该在视类中进行.回到视类注释掉,刚才我们添加在preCreateWindow函数中的代码.然后回到框架类的PreCreateWindow函数定义处.我们知道在框架类中只能修改窗口的图标,为实现这一功能我们需要重写整个窗口类,MFC为我们提供了一个全局函数AfxRegisterWndClass,用来设定窗口的类型,光标,背景和图标:LPCTSTR AFXAPI AfxRegisterWndClass(UINT nClassStyle,HCURSOR hCursor=0,HBRUSH hbrBackground =0,HICON hIcon =0);可以看到,该函数最后三个参数都有默认值.令我,它的返回值就是注册之后的类名,可以直接将这个返回值作为程序中随后创建窗口时所依赖的类.下面用这个函数来实现修改窗口的图标的功能,首先将CMainFrame类的PreCreateWindow函数中先前添加的代码注释起来,加入cs.lpszClass=AfxRegisterWndClass(CS_HREDRAW |CS_VREDRAW,0,0,LoadIcon(NULL,IDI_WARNING); 直接让cs的lpszClass成员等于AfxRegisterWndClass函数的返回值,并且因为在框架窗口中修改窗口类的光标和背景毫无意义,因此在调用这个函数时,直接将这两个参数设置为0,同时将窗口的图标设置为一个警告类型的图标IDI_WARNING.编译并运行,可以看到图标被改变了.因此,直接用这个函数比较方便,不用再去重新定义一个窗口类了.接下来在视类的PreCreateWindow函数中利用AfxRegisterWndClass函数修改视类窗口的背景和光标.cs.lpszClass=AfxRegisterWndClass(CS_HREDRAW |CS_VREDRAW,LoadCursor(NULL,IDC_CROSS),(HBRUSH)GetStockObject(BLACK_BRUSH),0); 在视类窗口中光标设置为十字状的,背景设置为黑色.同时,对于视类窗口来说,它本身并没有标题栏,所以也没有图标.编译运行,OK.接下来,将框架类和视类中的PreCreateWindow函数中两次调用的AfxRegisterWndClass函数时都只给其第一个参数赋值,其余都取默认值0. 我们得到的默认背景,是透明的,可以看到窗口下面窗口上的内容.默认的是箭头光标,默认的图标是波浪式WindowLogo图标. 在窗口创建之后修改: 使用全局API函数:SetClassLong来实现,该函数用来重置指定窗口类的WNDCLASSEX结构体(WNDCLASS结构的扩展)中指定数据成员的属性.DWORD SetClassLong(HWND hWnd,int nIndex,LONG dwNewLong); hWnd:指定要设置新属性的窗口句柄 nIndex:指定要设置的属性的索引:GCL_HBRBACKGROUND 设置新的背景画刷,GCL_HCURSOR 设置新的光标,GCL_HICON 设置新的图标,GCL_STYLE 设置新的窗口样式. dwNewLong:指定要设置的新的属性值. 首先,把我们之前写的代码注释掉.然后在CMainFrame类的OnCreate函数的最后,return之前添加SetClassLong(m_hWnd,GCL_HICON,(LONG)LoadIcon(NULL,IDI_ERROR); 同样是在框架类中只能修改窗口的图标.编译调试,OK. 在视类添加窗口的光标和背景.但是视类中没有自动创建OnCreate函数,我们要为该类添加WM_CREATE消息的响应函数.然后在这个函数中调用SetClassLong. int CStyleView:OnCreate(LPCREATESTRUCT lpCreateStruct) if (CView:OnCreate(lpCreateStruct) = -1) return -1; / TODO: Add your specialized creation code here SetClassLong(m_hWnd,GCL_HCURSOR,(LONG)LoadCursor(NULL,IDC_HELP); SetClassLong(m_hWnd,GCL_HBRBACKGROUND,(LONG)GetStockObject(BLACK_BRUSH); return 0; 模拟动画图标:首先准备好几个图标,然后在程序中每个一定的事件按顺序循环显示这几个图标,就实现了动画的效果.主要利用定时器和SetClassLong函数就可以完成这个功能.加载图标资源:将图标直接复制到res目录下,这里可以将随书光盘中的News.ico,User.ico和ZipFile.ico.复制到Style工程的res目录下,在VC+开发环境中选择InsertResource菜单名来,打开插入对话框,选择Import按钮,在弹出的导入资源对话框,找到res目录,然后选中我们复制的三个图标文件,单击Import来导入新的图标资源.这样Style程序中就有了三幅新的图标.这时我们程序中就有了三个新图标,IDI_ICON1,IDI_ICON2和IDI_ICON3.我们在Style程序的CMainFrame类中,定义一个图标句柄数组成员变量,来存放这三幅图标的句柄.private: HICON m_hIcons3; 然后在CMainFrame类的OnCreate函数中利用Load函数加载这三个图标. m_hIcons0=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_ICON1);m_hIcons1=LoadIcon(theApp.m_hInstance,MAKEINTRESOURCE(IDI_ICON2);m_hIcons2=LoadIcon(AfxGetApp()-m_hInstance,MAKEINTRESOURCE(IDI_ICON3); 首先加载IDI_ICON1,原来我们都是用的系统标准图标,所以以前LoadIcon函数的第一个参数为NULL,这里要使用我们自己定义的图标,第一个参数应该设置为应用程序的当前实例句柄.AfxGetInstanceHandle函数可以获得当前应用程序当前实例句柄.礼物LoadIcon第二个参数应该是图标的名称,或者图标资源标识符字符串,而我们只有图标资源的ID,这里必须通过MAKEINTRESOURCE宏将资源ID转换为响应的资源表示符字符串.这个宏的定义:LPTSTR MAKEINTRESOURCE(WORD wInteger);可以喊道这个宏的返回值是一个字符串类型,也就是字符指针类型.接下来加载第二幅图,本例中利用另一种方法来获得应用程序当前的实例句柄.MFC SDI应用程序中,有一个表示应用程序本身的类,本例是CStyleApp,它派生于CWinApp类.该类有一个数据成员m_hInstance,标识了应用程序的当前实例,也就是说,我们能获取到应用程序的CWinApp对象,就可以利用这个对象来调用它的m_hInstance数据成员,从而得到应用程序当前的实例句柄.根据前面知识,我们知道CStyleApp的源文件中已经定义了一个CStyleApp类型的全局变量:theApp.这样,我们就可以利用这个全局对象来调用其内部的数据成员.但是,在一个源文件中要想调用另一个源文件中定义的全局变量,必须在调用这个变量之前声明这个变量是在外部定义的.在CMainFrame类的OnCreate函数定义之前:extern CStyleApp theApp; 注意:该行代码不是在定义一个变量,而是在声明一个变量,声明这个变量是在外部的一个源文件中定义的.加载第三幅图标,我们换一种方式来获取应用程序当前的实例句柄.MFC提供了一个全局函数:AfxGetApp.可以获得当前应用程序对象的指针.因为这个函数是全局函数,所以在应用程序的任意地方都可以调用它.本例中,利用AfxGetApp函数返回值来访问应用程序的m_hInstance数据成员. 定时器的处理: 接下来设置定时器,本例设置为间隔1000毫秒触发一次定时器消息.因此,在CMainFrame类的OnCreate函数中添加: SetTimer(1,1000,NULL); 然后为CMainFrame类添加定时器消息(WM_TIMER)的响应函数,并在响应函数中调用SetClassLong函数. void CMainFrame:OnTimer(UINT nIDEvent) / TODO: Add your message handler code here and/or call default static int index=0; SetClassLong(m_hWnd,GCL_HICON,(LONG)m_hIconsindex); index=+index%3; CFrameWnd:OnTimer(nIDEvent); 首先定义了一个图标索引变量index,然后将其初始化为0;然后调用SetClassLong函数改变窗口的图标.本例要循环显示三幅图标,因此index这个索引值就需要在0,1,2这三个值之间循环变化.并且因为程序每次发送定时器消息后,就会调用OnTimer这个响应函数,因此应该把index变量定义为静态的.作为一个静态的局部变量,它将存放在程序的数据区中,而不是在栈中分配空间.当第一次调用OnTime函数时,系统会在数据区中为index变量分配空间,并根据它的定义初始化为0.当以后再次调用OnTimer函数时,因为indx变量的空间已经存在了,程序将之间引用该地址中已有的值. 本例也可以将它变为框架类的一个成员变量. 小技巧:如果希望把某个数值始终限定在一个范围内,那么最好的办法就是进行取模运算(%).例如,我们希望这个变量的取值在0-10之间变化,因为0-10之间有11个数,所以我们就应该把这个变量对11取模.实际上,取模运算就是取余. 上述代码,SetClassLong函数的第三个参数需要一个LONG型的值,而m_hIconsindex是HICON类型,需要一个强制转换. 编译运行,得到了我们想要的结果,但是程序启动时显示的是应用程序原来的图标,然后才开始循环我们自定义的三幅图标.因此,我们应该在框架类的OnCreate函数中,在加载图标之后,就应该调用SetClassLong函数将应用程序的图标设置为我们自定义的第一个图标.然后将OnTimer函数中的,index变量初始值改为1. m_hIcons0=LoadIcon(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDI_ICON1);m_hIcons1=LoadIcon(theApp.m_hInstance,MAKEINTRESOURCE(IDI_ICON2);m_hIcons2=LoadIcon(AfxGetApp()-m_hInstance,MAKEINTRESOURCE(IDI_ICON3);SetClassLong(m_hWnd,GCL_HICON,(LONG)m_hIcons0);SetTimer(1,1000,NULL); return 0; 工具栏编程: 工具栏是Window应用程序中一个非常重要的图形界面元素,它提供了一组顺序排列的带有位图图标的按钮.工具栏是把常用的菜单命令集合起来,以按钮的形式提供给用户使用.在Style工程中,在ResourceView选项卡的Toolbar文件夹下有一个工具栏资源:IDR_MAINFRAME,单击这个资源ID,即可在资源编辑窗口中打开工具栏资源. 为了查看工具栏上某个按钮的属性,可以在资源编辑窗口中,在该按钮上双击鼠标左键,即可弹出该按钮的属性对话框.我们打开几个按钮的属性,可以发现它们的ID与子菜单中的菜单项的ID都是相同的. 在工具栏上添加和删除按钮: 方法是在最后一个空白按钮上单击,然后在按钮编辑窗口,用工具面板上提供的绘图工具设计按钮的外观.本例添加的按钮ID设置为IDM_TEST.然后在菜单资源的帮助子菜单下添加一个菜单项,并将其ID设置为刚才新添加的那个按钮的ID.Caption设置为:Test.接着,我们为这个菜单项添加一个命令响应函数:MessageBox(“test”); 可以看出,在Style程序的工具栏上有些按钮之间有一条竖线,这个称为”分隔符”.主要用来分隔按钮.前三个表示为文件子菜单下的菜单命令.接下来的是编辑子菜单下的菜单命令.为了加一条分隔符,我们可以在资源编辑窗口中,用鼠标将我们制作的按钮向右拖动一点距离后松开鼠标,这时看到我们的图标和其他的之间有了缝隙.再编译运行,我们就可以看到分隔符了. 如果想删除工具栏上的某个按钮时,如果直接按Del按钮,这样只会删除按钮上的图像,如果要删除工具栏上的按钮,方法是在资源编辑窗口中,在此按钮上按下鼠标左键,然后将该按钮拖出工具栏,然后松开鼠标左键,就OK了. 创建工具栏: Style程序中,在CMainFrame类的头文件中定义了一个CToolBar类型的成员变量:m_wndToolBar,CToolBar就是工具栏类.它派生于CControlBar类,后者又派生鱼CWND类,因此工具栏也是一个窗口. 1.创建工具栏的方法 (1)第一种方法: 1创建工具栏资源2构造CToolBar对象3调用Create或CreateEx函数创建Windows工具栏,并把它与已创建的CToolBar对象关联起来4调用LoadToolBar函数加载工具栏资源:BOOL Create(CWnd* pParentWnd,DWORD dwStyle =WS_CHILD | WS_VISBLE |CBRS_TOP,UINT nID =AFX_IDW_TOOLBAR); nParentWnd:CWnd类型的指针,指定工具栏对象的父窗口.dwStyle:指定工具栏的样式,例如工具栏是一个子窗口(WS_CHILD),工具栏是可视的(WS_VISIBLE),工具栏停靠在框架窗口的顶部(CBRS_TOP).nID:指定工具栏子窗口的ID.CToolBar类的CreateEx成员函数:BOOL CreateEx(CWnd* nParentWnd,DWORD dwCtrStyle = TBSTYLE_PLAT,DWORD dwStyle = WS_CHILD | WS_VISIBLE | CBRS_ALIGN_TOP,CRect rcBorders =CRect(0,0,0,0),UNIT nID =AFX_IDW_TOOLBAR); pParentWnd:CWnd类型指针,指定工具栏对象的父窗口. dwCtrStyle:设置内嵌在工具栏上的CToolBarCtrl对象创建时的扩展风格,该参数默认值为TBSTYLE_FLAT. dwStyle:与Create函数同名参数相同,用来指定工具栏样式. rcBorders:定义工具栏窗口的边框宽度. nID:与Create函数同名参数相同,用来指定工具栏子窗口的ID;(2)第二种方法:1构造CToolBar对象.2调用Create或CreateEx函数创建Window工具栏,并把它与已创建的CToolBar对象关联起来.3调用LoadBitmap函数加载包含工具栏按钮图像的位图.先前在程序中看到的工具栏资源:IDR_MAINFRAME,在保存时是以一幅位图的形式保存的,该位图名称为ToolBar.bmp,位置是在当前工程所在目录下的res目录下.这幅位图上有许多小的图像,它们分别对应工具栏上的各个按钮.4调用SetButtons函数设置按钮样式,并把工具栏上的一个按钮与位图中的一个图像相关联.MFC创建工具栏的过程:在Style程序中,MFC AppWizard自动产生的与工具栏对象相关的代码存在于CMainFrame类的OnCreate函数中.int CMainFrame:OnCreate(LPCREATESTRUCT lpCreateStruct) 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(Failed to create toolbarn); return -1; / fail to create if (!m_wndStatusBar.Create(this) | !m_wndStatusBar.SetIndicators(indicators, sizeof(indicators)/sizeof(UINT) TRACE0(Failed to create status barn); return -1; / fail to create / TODO: Delete these three lines if you dont want the toolbar to / be dockable m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY); EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_wndToolBar); 在CMainFrame类的OnCreate函数中,首先调用CreateEx函数创建程序的工具栏对象,接着调用LoadToolBar函数加载工具栏资源IDR_MAINFRAME知识点:MFC为我们自动创建的工具栏和主菜单的资源ID是一样的,也就是说在MFC编程中,一个ID可以表示很多资源.接着CMainFreme类的OnCreate函数调用工具栏对象的EnableDocking成员函数设置工具栏停靠的位置:接下来,CMainFrame类的OnCreate函数又调用了一个EnableDocking函数. 先前一次调用的EnableDocking函数是工具栏对象的成员函数,目的是让工具栏对象可以停靠,而这里调用的是CFrameWnd对象的EnableDocking成员函数,目的是让主框架窗口可以被停靠.最后CMainFrame类的OnCreate函数调用DockControlBar函数,让工具栏停靠在主框架窗口上.创建自定义的工具栏:按照第一种方法创建工具栏,首先为Style函数掺入一个新的工具栏资源,选择InsertResource菜单命令,在弹出的插入资源对话框中选择ToolBar资源类型,然后选择New.另一种插入新工具栏资源的方法是,在工程的ResourceView选项卡上,在ToolBar文件夹上单击鼠标右键,从弹出的快捷菜单中选择Insert Toolbar菜单命令,即可插入新的工具栏资源.无论哪种方法,VC+都会在Style程序中插入一个名为IDR_TOOLBAR1的工具栏资源,并且该工具栏上只有一个空白的按钮.然后我们可以根据需要在该按钮上绘制图形.本例在新工具栏上再添加2个按钮,并分别为这三个按钮绘制图形:矩形,椭圆和圆形.按照上面的步骤,下一步我们要构造一个CToolBar对象,也就是为CMainFrame类添加一个CToolBar类型的成员变量CToolBar m_newToolBar;.然后调用Create或CreateEx函数创建工具栏,并与CToolBar对象相关联,这可以在CMainFrame类的OnCreate函数中实现,我们继续在上次添加的代码后添加: if (!m_newToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_RIGHT | CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) | !m_newToolBar.LoadToolBar(IDR_TOOLBAR1) TRACE0(Failed to create toolbarn); return -1; / fail to create m_newToolBar.EnableDocking(CBRS_ALIGN_ANY); DockControlBar(&m_newToolBar);首先调用CToolBar的成员函数:CreateEx创建工具栏,并与工具栏对象m_newToolBar相关联,这里将新工具栏的停靠位置设置为CBRS_RIGHT,然后调用LoadToolBar函数加载我们刚刚新建的工具栏资源IDR_TOOLBAR1.接着调用工具栏对象EnableDocking函数允许工具栏停靠于客户区的任意位置(ALIGN_ANY).因为在OnCreate函数的前面已经调用了框架类的EnableDocking函数,让主框架可以被停靠,然后这里就不需要调用这个函数了.新添加代码最后调用框架类的DockControlBar函数,让这个新工具栏停靠在主框架窗口上. 编译运行.OK.因为我们没有为按钮设置关联,所以新建的三个按钮都是灰色的. 当我们单击Style程序的查看工具栏菜单命令,将会发现程序原来由MFC帮助我们产生的那个工具栏从窗口中消失了,再次单击,工具栏又显示了.下面我们要对刚才添加的工具栏实现同样的功能,首先为Style程序再添加一个菜单项,通过该菜单项来隐藏或显示刚才新建的那个工具栏.并且要为该菜单项设置一个复选标记,当这个新工具栏出现时,该菜单项带有这个复选标记;当这个新工具栏消失时,该菜单项没有这个复选标记.本例在Style程序的查看子菜单下添加一个菜单项,将其ID属性设置为IDM_VIEW_NEWTOOLBAR,Caption设置为”新的工具栏”.接着为CMainFrame类添加对这个菜单项的命令响应函数,并再次函数中,实现先前新建的那个工具栏的显示和隐藏.我们提过,工具栏本身也是一个窗口,可以调用CWnd类的ShowWindow函数让其显示或隐藏. void CMainFrame:OnViewNewtoolbar() / TODO: Add your command handler code here if(m_newToolBar.IsWindowVisible() m_newToolBar.ShowWindow(SW_HIDE); else m_newToolBar.ShowWindow(SW_SHOW); 首先判断新工具栏的当前状态,是显示还是隐藏的,如果显示的,将它隐藏,如果是隐藏的,那就让它显示.编译运行,选择查看新的工具栏可以发现窗口右边的新工具栏上的按钮消失了,但是这个工具栏仍然存在.这是因为当窗口上的工具栏被隐藏或显示后,停靠在窗口上的其他控制条对象的位置可能会有所改变,这时需要调用框架类的RecalcLayout成员函数来重新调整一下它们的位置:Virtual void RecalcLayout(BOOL bNotify = true);该函数有一个BOOL类型的参数:bNotify,如果参数为真表示框架窗口上活动的对象会收到布局变动通知,如果为假,则不会收到.默认值是true.因此,我们在CMainFrame类OnViewNewtoolbar函数中最后添加RecalcLayout();编译,运行,OK.但当我们拖动新工具栏到某一位置,然后选择查看新的工具栏菜单命令,会发现此时程序又出问题了,这个工具栏上的按钮消失了,但工具栏仍存在.实际上,当工具栏再次显示或隐藏后,需要再次调用框架类的DockControlBar函数,让工具栏停靠在主框架窗口上.因此要在CMainFrame类的OnViewNewtoolbar函数的最后再调用一次框架类的DockControlBar函数.DockControlBar(&m_newToolBar);编译运行,ok.我们发现当把新工具栏拖到窗口中央,让其因此,然后再让它显示,它会停靠在客户区的顶部.如果我们把Style程序中AppWizard自动创建的那个工具栏拖动到窗口中间的某个位置,让其处于一种浮动状态,然后让它消失,然后再让它显示,发现这个工具栏在先前浮动位置又显示出来了.对于我们的新工具栏,我们需要使用ShowControlBar函数来实现,它是CFrameWnd类的成员函数.用来隐藏或显示指定的控制条.void ShowControlBar(CControlBar* pBar, BOOL bShow,BOOL bDelay);pBar:CControlBar类型的指针,指向要显示或隐藏的控制条.CToolBar类派生于CControlBar类.bShow:布尔类型,其值如果为true,表示显示指定的控制条.如果为false,表示隐藏指定的控制条.bDelay:如果为TRUE,延迟显示控制条,如果为false,立即显示控制条.这样我们就可以将CMainFrame类的OnViewNewtoolbar函数中已有代码注释起来或删除:void CMainFrame:OnViewNewtoolbar() / TODO: Add your command handler code here ShowControlBar(&m_newToolBar,!m_newToolBar.IsWindowVisible(),FALSE); 上述新添代码通过调用工具栏对象的IsWindowVisible成员函数,获得工具栏当前的状态,如果该函数为true,说明工具当前是显示状态,那么这时应该隐藏工具栏,也就是说这时ShowControlBar函数的第二参数应该为false,如果该函数的返回值为false,则说明工具栏当前是隐藏状态,那么这时应该显示该工具栏,也就是说,这时ShowControlBar函数的第二个参数应该为true.编译运行,达到预期效果综合比较一下,使用ShowControlBar函数比较简单,一个函数就能搞定.下面为刚才添加的名称为”新的工具栏”的菜单项设置复选标记,隐藏需要为这个菜单项添加一个UPDATE_COMMAND_UI消息响应函数,通过ClassWizard来完成,同样在框架类中.void CMainFrame:OnUpdateViewNewtoolbar(CCmdUI* pCmdUI) / TODO: Add your command update UI handler code here pCmdUI-SetCheck(m_newToolBar.IsWindowVisible(); 这里利用工具栏对象的IsWindowVisible函数返回值来设置是否显示复选标记.如果返回TRUE,表示工具栏是显示状态.编译运行,OK.预期效果. 通过为菜单项添加UPDATE_COMMAND_UI消息响应,可以非常方便地为该菜单项设置或取消复选标记.状态栏编程:状

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论