vc界面编程经典实例1.pdf

上传人:qwe****56 文档编号:69996723 上传时间:2023-01-13 格式:PDF 页数:144 大小:701.64KB
返回 下载 相关 举报
vc界面编程经典实例1.pdf_第1页
第1页 / 共144页
vc界面编程经典实例1.pdf_第2页
第2页 / 共144页
点击查看更多>>
资源描述

《vc界面编程经典实例1.pdf》由会员分享,可在线阅读,更多相关《vc界面编程经典实例1.pdf(144页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。

1、A A A A DragDragDragDrag andandandand DropDropDropDrop ListListListList ControlControlControlControl程序运行效果截图:这篇文章包含一个 demo project,一个继承于 CListCtrl 的类和一个快速查看这个类功能的 release。我不想让这个类十全十美,但对于我当前的项目来讲,它的功能已经足够了。当然了,它还有更进一步完善的地方,欢迎指正!左图是程序演示的示例图片。类 CDragDropListCtrl 具有以下的功能和特性:1、支持单选和复选的任意托拽2、所选择的托拽目标跟随这鼠标

2、突现式的移动3、当把目标托出上下边界的时候,List Control 会自动滚动4、以 LVS_EX_FULLROWSELECT 风格的开关方式运行、5、保存所托拽目标的状态6、所有的代码都封装在 control 当中无需修改父类本类源自 Wayne Berthin 以前写过的一篇文章,但我重写了大部分代码,并且又增加了很多。CreateDragImageEx 方法跟 Frank Kobs 所给出的大致相同,但修复了一个小的 bug 以便于程序能更好的运行。要使用这个类,首先要把 DragDropListCtrl.cpp 和 DragDropListCtrl.h 两个文件添加到你的工程当中,然

3、后在你的对话框资源中增加一个List Control,并设置 View 方式为 Report,用 ClassWizard 为这个 List Control 添加一个变量,变量的类别为 Control,变量类型为CDragDropListCtrl,最后,把下面一行加到你的对话框头文件的顶部:#include DragDropListCtrl.h这样就大功告成了!MFCMFCMFCMFC 窗口位置管理详细分析及实例窗口位置管理详细分析及实例在一般用 MFC编写的程序的窗口客户区中,可能有好几个子窗口(具有 WM_CHILD风格的窗口)。上边是工具栏,中间是视图窗口,下边是状态栏。三个窗口在框架的客

4、户区里和平共处,互不重叠。主框架窗口的尺寸改变了,别的子窗口都能及时调整自己的尺寸以便保持相互位置关系不变,例如状态条窗口总能保持在主框架客户区底部,并且其宽度总能和主框架客户区宽度一致。工具栏窗口总能停靠在主框架的某一边不变,其宽度或高度总能和主框架客户区的宽度或高度一致,视图窗口总能填满主框架客户区的剩余空间。假如我们自己从 CWnd 类派生一个窗口类并生成一个窗口,在它的客户区里要生成若干个子窗口,我们想使这些子窗口排列得规规矩矩,互不重叠,当父窗口的尺寸变了时各个子窗口能适时调整自己的尺寸和位置,使各个子窗口之间的位置大小比例关系不变。当移动其中一个或几个子窗口时,别的子窗口能及时为这

5、个移动了的子窗口让位。当然我们可以利用 api 函数里管理窗口的函数来编写自己的管理子窗口的方法。可是如果在父窗口的客户区里有了工具栏,状态条等等子窗口时,你自己加进来的子窗口还能和这些 mfc提供的子窗口融洽相处吗?你如何保证你的子窗口不会覆盖了能够四处停靠的工具栏?当工具栏和状态条消失后你的子窗口如何才能知道,以便及时调整自己的大小从而覆盖工具栏和状态条腾出的空间?基于文档视图构架的窗口的客户区内还有个视图,你自己硬加上的子窗口能不和视图窗口争地盘吗?所以必须了解 mfc 的窗口管理它的客户区的方法。其实,mfc 的窗口管理它的客户区的方法是非常简单的:父窗口调用一个函数,子窗口响应一个消

6、息,就这么多。CWnd:RepositionBars 函数和 WM_SIZEPARENT 消息先简述一下 mfc 的窗口为子窗口分配客户区空间的过程:这一过程是父窗口与子窗口共同协调完成的。父窗口先提供它的客户区内的一块区域,叫做起始可用区域。然后调用一个函数,在这个函数里,父窗口把这片区域通过一个消息提交给它的第一个子窗口,该子窗口决定自己要占用多大一块,然后在可用区域里把它将占据的部分划出去,这样可用区域就被切去了一块。父窗口再把这块剩下的可用区域通过同样的消息提交给第二个子窗口,第二个子窗口再根据自己的需要切掉一块。如此这般,每个子窗口都切去自己所需的一块。最后剩下的可用区域就给最后的子

7、窗口使用。可以看出,除了最后一个子窗口外,其它子窗口都得在消息响应函数里有自己的算法来决定自己将在可用区域里占据多大一块,最后一个子窗口由于别无选择,所以不需要这样的算法。当然,初始的可用区域是一个矩形,每次被切割后剩下的可用区域还是一个矩形,不可能是别的形状的。举例说来,在一个典型单文档程序中,父窗口就是从 CFrameWnd 派生的主框架窗口,最后一个子窗口就是视图窗口,如果用了 CSplitterWnd 生成分隔条的话,最后一个子窗口就是拥有分隔条的那个窗口。其它子窗口就是工具栏窗口和状态条窗口,以及可能有的别的控件窗口。在典型多文档界面程序中,父窗口就是主框架窗口,最后一个子窗口就是覆

8、盖在主窗口客户区,背景为黑灰色,拥有包含文档的子框架窗口的那个窗口,这是个预定义了窗口类的窗口,它的窗口类名是“MDIClient”。如果用了 CSplitterWnd 生成分隔条的话,最后一个子窗口就是拥有分隔条的那个窗口。其它窗口就是工具栏窗口,状态条窗口以及可能有的别的控件窗口。这个函数和消息是:函数 CWnd:RepositionBars()以及消息 WM_SIZEPARENT。这个消息是 mfc 自定义的,不是 windows自有的。先简单说明一下这个函数和消息。1。函数 CWnd:RepositionBars()这个函数不是虚函数,所以就无法在派生类里通过覆盖来编制自己的版本了,只

9、能搞懂它的功能,以便能灵活使用。简单而言,这个函数的功能是将可用的客户区区域信息放到消息 WM_SIZEPARENT 的消息参数里,然后枚举本窗口的所有子窗口,给每个子窗口(除掉一个特定的子窗口,相当于上文提到的最后一个子窗口)都发送这个消息,每个响应这个消息的子窗口都会把可用客户区切去一块。最后把那个特定的子窗口的尺寸和位置调整到刚好放在最后剩下的可用区域里。2。消息 WM_SIZEPARENT每个欲参与分配客户区的子窗口都要响应这个消息,除非这个子窗口是那个特定的子窗口。响应这个消息的子窗口至少要做两件事:1,将可用的父窗口客户区切去自己所占据的一块。2,根据消息参数的指示,将自己的大小和

10、位置调整到刚好容纳到自己所占据的区域里或不做调整。下面详细介绍一下函数 CWnd:RepositionBars()和消息 WM_SIZEPARENT。1。函数 CWnd:RepositionBars()void RepositionBars(UINT nIDFirst,UINT nIDLast,UINT nIDLeftOver,UINTnFlag=CWnd:reposDefault,LPRECT lpRectParam=NULL,LPCRECT lpRectClient=NULL,BOOL bStretch=TRUE);参数比较多,但还是比较好懂的。(1)nIDFirst 和 nIDLast参

11、与分配父窗口客户区的子窗口的 id 范围。每个 WM_CHILD 风格的窗口都有个 id,这是在窗口创建过程中指定的。函数 CWnd:Create()的第六个参数就是这个 id。api函数 CreateWindow 和 CreateWindowEx 里的那个 HMENU类型的参数,当窗口的风格里有 WM_CHILD 时,它不是指的菜单句柄,而是该窗口的 id。nIDFirst 和 nIDLast 参数指明了:如果一个子窗口的 id 值大于等于 nIDFirst 并且小于等于 nIDLast,在这个函数中才会给这个子窗口发送 WM_SIZEPARENT 消息,这个子窗口才能参与父窗口客户区的分配

12、。(2)nIDLeftOver前面说过,有一个特定的子窗口,它不响应 WM_SIZEPARENT 消息。只有当其它的子窗口都分配完了,它才来捡取父窗口客户区里剩下的那块。nIDLeftOver 正是这个子窗口的 id。它也必须大于等于 nIDFirst并且小于等于 nIDLast。(3)lpRectClient这是一个指向 RECT 结构数据的指针。这个 RECT 结构里存放的正是父窗口客户区的初始可用区域。随着在该函数里依次给各个子窗口发送 WM_SIZEPARENT 消息,每个响应这个消息的子窗口都会切去自己所占据的部分。最后剩下的部分,就是 id 为 nIDLeftOver 的子窗口将要

13、占据的区域了。这个参数可以为 NULL,这时初始的可用区域就是整个父窗口客户区。(4)nFlag 和 lpRectParam这两个参数放在一起讲比较好。nFlag 是该函数的功能标志,它可以有三个值:reposDefault,reposQuery 和reposExtra。当 nFlag 等于 reposDefault 时,RepositionBars 函数的功能是这样的:依次给 id 介于 nIDFirst 和 nIDLast 之间并且不等于 nIDLeftOver 的子窗口发送 WM_SIZEPARENT 消息,每个响应这个消息的子窗口 从lpRectClient 所指的结构里切去自己所占据

14、的部分,并且将自己的大小和位置调整到自己所占据的区域的大小,最后 RepositionBars 函数还将 id 为 nIDLeftOver 的子窗口的大小和位置调整到被其他子窗口切剩的可用区域内,使这个子窗口正好完全覆盖最后的可用区域。这种情况下 lpRectParam 不用,可以为 NULL。当 nFlag 等于 reposQuery 时,RepositionBars 函数的功能是这样的:依次给 id 介于 nIDFirst 和 nIDLast 之间并且不等于 nIDLeftOver的子窗口发送WM_SIZEPARENT 消息,每个响应这个消息的子窗口从lpRectClient所指的结构里切

15、去自己所占据的部分,但是他们并不调整自己的大小和位置,最后 RepositionBars 函数并不调整将id为nIDLeftOver的子窗口的大小和位置,而是根据bStretch的值来做动作:如果bStretch为TRUE,那么 RepositionBars 函数把最后剩下的可用区域拷贝到 lpRectParam 指向的 RECT 结构里;如果 bStretch 为FALSE,那么 RepositionBars 函数把所有其他子窗口占用掉的可用区域的高和宽(要所有的子窗口都紧排在一起,形成一个大的矩形,这个值才有意义)拷贝到 lpRectParam 指向的 RECT 结构的 bottom 和

16、right 成员里,其 top和 left 成员被置零。使用这个 nFlag 值来调用 RepositionBars 的目的不是要重排子窗口,而是要看看,假如重排子窗口的话,这些子窗口将占去多大一块,最后剩下的可用区域在什么位置等等信息。当 nFlag 等于 reposExtra 时,该函数的功能和 nFlag 等于 reposDefault 时差不多,有点小小的区别。此时需要用到 lpRectParam。前面说过,当 nFlag 等于 reposDefault 时,RepositionBars 函数将在最后把 id 为nIDLeftOver 的子窗口的大小和位置调整到被其他子窗口切剩的可用区

17、域内,使这个子窗口正好完全覆盖最后的可用区域。而当 nFlag 等于 reposExtra 时,RepositionBars 在调整 id 为 nIDLeftOver 的子窗口的大小和位置前,还要用 lpRectParam 来对最后剩下的可用区域做修正。假设 lpRect 指向的是最后的可用区域,那么这个修正是这样进行的:lpRect-top+=lpRectParam-top;lprect-left+=lpRectParam-left;lpRect-right-=lpRectParam-right;lpRect-bottom-=lpRectParam-bottom;通过这样的修正,可以使最后剩

18、下的可用区域不被 id 为 nIDLeftOver 的子窗口占满,而是空出一些地方来留作他用。(5)bStretch这个参数上面已经提到一点它的作用。它主要是提供给各个响应 WM_SIZEPARENT 消息的子窗口用的,子窗口例如工具栏,状态条等在决定自己将从父窗口客户区的可用空间里划走多少时,这个参数也是个判断的依据。详细可以参阅工具栏和状态条响应 WM_SIZEPARENT 的函数 OnSizeParent()。2。消息 WM_SIZEPARENT这是个 mfc 自定义的消息。在 msdn 里的 TN024 这篇技术文章里有关于这个消息的说明。该消息的两个参数中 wParam 不用,lPa

19、ram 是指向一个 AFX_SIZEPARENTPARAMS结构变量的指针,这个结构变量是在 RepositionBars 函数里定义的:AFX_SIZEPARENTPARAMSlayout;AFX_SIZEPARENTPARAMS结构定义如下:struct AFX_SIZEPARENTPARAMSHDWPhDWP;RECT rect;SIZE sizeTotal;BOOLbStretch;这个结构变量的成员是在 RepositionBars 函数里填写的:它的 bStretch 成员就是 RepositionBars 的参数bStretch,它的 sizeTotal 成员的两个成员 cx 和

20、 cy 都被设置为零,它的 rect 成员就是从 RepositionBars 的参数 lpRectClient 里拷贝过来的,就是父窗口客户区的初始可用区域嘛。每个响应这个消息的子窗口都必须修改 rect 成员的值,以便切去自己所占据的部分。成 员 hDWP 是 什 么?这 得 知 道 三 个 api 函 数:BebinDeferWindowPos(),DeferWindowPos()和EndDeferWindowPos()。这三个 api 函数是用来成批设置窗口的位置和尺寸的。BebinDeferWindowPos()先通知 windows分配一个将用来存贮窗口的位置和尺寸信息的结构,它不

21、是返回这个结构的指针,而是返回代表这个结构的句柄,句柄的类型是 HDWP。然后每个需要重新设置位置和尺寸的窗口都要调 用DeferWindowPos()函数(该函数需要那个 HDWP 类型的句柄为参数),以便往那个结构里填写各自的窗口位置和大小信息。最后,在某个合适的时候调用 EndDeferWindowPos(),windows就会根据那个结构里的信息把有关的窗口的位置和大小一次性设置好。比起针对每个窗口分别用 SetWindowPos()等函数逐个设置来说,这种方法速度快。好了,在 RepositionBars 函数里正是调用了 BebinDeferWindowPos(),获得一个 HDW

22、P 类型的句柄,这个句柄就被填写到了上面那个结构变量 layout 的成员 hDWP 里。然后 RepositionBars 函数给每个符合条件的子窗 口 发 送 WM_SIZEPARENT 消 息。在每 个 响 应 WM_SIZEPARENT 消 息 的 子窗 口 里,要 调 用DeferWindowPos()来设置位置和尺寸信息。当所有的子窗口都响应完毕 WM_SIZEPARENT 消息后,RepositionBars 函数再调用 EndDeferWindowPos()函数,这一来,除了那个 id 为 nIDLeftOver 的子窗口外,所有的子窗口都一次性排好了位置了。至于该结构的 si

23、zeTotal 成员的意义,它累计每个子窗口所占据掉的可用区域的长宽尺寸和。每个子窗口在响应WM_SIZEPARENT 消息时一般都要把自己所占据的区域的高和宽分别累加到sizeTotal结构的cy和cx成员里。这有什么意义呢?当每个子窗口所占据的区域都是挨在一起的时候,这个 sizeTotal 结构就有意义了,主框架窗口可以使 nFlag 等于 reposQuery,使 bStretch 等于 FALSE 来调用 RepositionBars 函数,RepositionBars 函数会把 sizeTotal 结构的两个成员值拷贝到 lpRectParam 参数里返回给主框架类(前面也提到过)

24、,这样主框架类就知道它的客户区内的子窗口占去了客户区内多大的一块空间。如果你的主框架窗口没有利用这个信息,那么响应 WM_SIZEPARENT 消息的子窗口就可以不理睬 sizeTotal 成员。ID 的分配可以看到,每个子窗口都有个 id,同一个父窗口的子窗口的 id 不能重复。mfc 的一些现成的控件子窗口都有预定义的 id:id 名 id 值 意义AFX_IDW_TOOLBAR0 xE800/主窗口的工具栏的 idAFX_IDW_STATUS_BAR 0 xE801/状态栏的 idAFX_IDW_PREVIEW_BAR 0 xE802/PrintPreview Dialog BarAFX

25、_IDW_RESIZE_BAR0 xE803/OLE in-place resize barAFX_IDW_REBAR 0 xE804/COMCTL32 rebar BarAFX_IDW_DIALOGBAR 0 xE805/CDialogBar还有象单文档程序的视图窗口,多文档程序的那个 MDIClient 窗口,分隔条窗口,他们的 id 值介于下面两个 id 值之间:AFX_IDW_PANE_FIRST 0 xE900/AFX_IDW_PANE_LAST 0 xE9FF你要给你自己的子窗口分配 id 的话,别和上面的重复了。一般如果用 IDE 的菜单 view/resource symbol

26、s 项来加入自己的 id 的话,是不会重复的。有关 id,还可以看看 msdn 里的 TN020 文章,那是专讲 id 的。实例分析1。CFrameWnd 类是如何调用 RepositionBars 函数的前面介绍了 RepositionBars 的各个参数和意义,现在看看 CFrameWnd 类是如何调用这个函数的,从中可以学习 RepositionBars 函数的使用方法。CFrameWnd 类及其派生类生成的窗口的客户区内可以有工具栏,状态条和视图窗口等子窗口。当父窗口的尺寸发生变化时,这些子窗口的各自的位置和大小比例关系保持不变,这就需要父窗口一旦在它自己的尺寸发生变化时就调用 Rep

27、ositionBars 函数。CFrameWnd类是集中在函数 RecalcLayout 里调用 RepositionBars函数的。该类保证了在窗口尺寸发生变化时函数 RecalcLayout 都被调用,从而 RepositionBars 函数也能被及时调用,确保了各个子窗口都能及时调整自己的位置和大小。RecalcLayout 是个虚函数。该函数的功能就是在主框架的客户区内提供一个初始的可用区域,并把这个区域放在一个 CRect 类型的变量里。该函数大致是这样的:void CFrameWnd:RecalcLayout(BOOL bNotify)if(m_bInRecalcLayout)re

28、turn;/这大概是在防止该函数重入m_bInRecalcLayout=TRUE;.if(GetStyle()&FWS_SNAPTOBARS)CRect rect(0,0,32767,32767);RepositionBars(0,0 xffff,AFX_IDW_PANE_FIRST,reposQuery,&rect,&rect,FALSE);RepositionBars(0,0 xffff,AFX_IDW_PANE_FIRST,reposExtra,&m_rectBorder,&rect,TRUE);CalcWindowRect(&rect);SetWindowPos(NULL,0,0,re

29、ct.Width(),rect.Height(),SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);elseRepositionBars(0,0 xffff,AFX_IDW_PANE_FIRST,reposExtra,&m_rectBorder);m_bInRecalcLayout=FALSE;可以看出,mfc 认为这个函数是不能重入的。在编制自己的 RecalcLayout()函数时也得用同样的方法来防止重入。后面的 if 语句检查框架窗口是否具有风格 FWS_SNAPTOBARS,这个风格用在什么时候呢?我是这样认为的:通常都是在主框架窗口的尺寸改变时,子窗口

30、在响应 WM_SIZEPARENT 消息时调整自己的尺寸以便跟上框架窗口的尺寸变化。有这样的情况:父窗口的客户区内的子窗口的数目是动态变化的,而且这些子窗口互相不能重叠,他们的尺寸由于某种原因不好改变。那么当子窗口的数目发生增减时,如不调整父窗口自己的尺寸,就会导致客户区留下空白或新增加的子窗口没有多余空间安排。FWS_SNAPTOBARS 风格就是用在这种情况下,使父窗口能调整自己的大小以便容纳子窗口。看这个分支里的语句,似乎是这样的。一般都不会有 FWS_SNAPTOBARS 风格的,所以一般是执行 else 分支。在这个分支里简单地调用RepositionBars 去重排所有的子窗口,它

31、的参数lpRectClient 使用默认的 NULL 值,意思就是初始可用区域是父窗口的整个客户区。可以在自己的派生类里编写自己的 RecalcLayout 函数,以便用自己的方法调用 RepositionBars 函数。要注意的是在 CFrameWnd 类的窗口刚被创建时 RecalcLayout 函数也被调用,此时可能某些用户自己加的子窗口还未被创建出来,所以在这个函数内如果要引用某个用户自己加的子窗口的句柄的话必须先用:IsWindow()函数判断一下该窗口句柄是否可用。否则的话就会出现非法操作了。实战演练由于精力有限,只提供一个实战例子:将视图,工具栏和状态栏赶到右边我们要生成这样的界

32、面:视图窗口,工具栏和状态条统统在右边,左边是个自己加的窗口。第一步:启动 AppWizard生成一个单文档程序,全部使用默认设置。第二步:在 CMainFrame 类里增加一个成员 CWnd m_mywnd。第三步:在 CMainFrame:OnCreate()函数里增加这几行:m_mywnd.CreateEx(WS_EX_CLIENTEDGE,AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW,:LoadCursor(NULL,IDC_ARROW),:CreateSolidBrush(RGB(190,190,190),WS_VISIBLE|WS_CHILD,

33、CRect(0,0,0,0),this,IDC_MYPANE/用 IDE 的菜单 view/resource symbols 项加入的 id。);第四步:启动 ClassView,在 CMainFrame 里加上虚函数 RecalcLayout(),函数体这样写:void CMainFrame:RecalcLayout(BOOL bNotify)if(m_bInRecalcLayout)return;m_bInRecalcLayout=TRUE;/rect1 是新加的窗口将占据的区域/rect2 就是提供给工具栏,状态条和视图窗口的初始可用区域。CRect rect1,rect2;GetCli

34、entRect(&rect1);rect1.right=rect1.right/3;GetClientRect(&rect2);rect2.left=rect2.right/3;if(:IsWindow(m_mywnd.m_hWnd)/这句是不能少的m_mywnd.MoveWindow(&rect1);RepositionBars(0,0 xffff,AFX_IDW_PANE_FIRST,reposExtra,CRect(0,0,0,0),&rect2);m_bInRecalcLayout=FALSE;第五步:用 IDE 的菜单 view/resource symbols 项加入一个 id:I

35、DC_MYPANE。第六步:编译并运行程序。好了,在主框架窗口的左边多了一个灰色的窗口,它占主窗口客户区的三分之一。工具栏,状态条和视图都被赶到右边三分之二的地方去了。ToolbarToolbarToolbarToolbar 制作菜单条过程详解制作菜单条过程详解现在许多用户界面都使用工具栏制作菜单条,小弟最近对此感兴趣,便从网上求助,可是得到的帮助大多是 BCGControlBar 的源代码或者是 SizableRebar 的源代码,对于只希望是自己的界面具有该功能的朋友来说,这也许是不错的选择,只要看一下 demo,然后直接调用别人的类库就可以了,但对于我等对此话题感兴趣,希望弄懂其来龙去脉

36、的读者来说,直接看这些没有详细解释的源代码,要从中弄出个所以然来,实不是件容易的是,至少对于像我这样的菜鸟来说是这样的,本文出于此种原因,希望对还在寻求此帮助的读者能提供一些帮助。下面我们边看边侃:在接收到 toolbarbutton 按下消息时,我们一般使用 TrackPopupMenuEx 弹出菜单,问题的关键是,在菜单未关闭时,TrackPopupMenuEx 并不返回,并拦截鼠标和键盘消息,使用 spy 可以看到,此时的工具栏收不到任何消息,当然无从改变热点,这就需要我们自己探测鼠标位置并在鼠标移动到下一个热点时关闭上一个菜单并显示下一个菜单。这里我们使用钩子函数 SetWindows

37、HookEx 在调用 TrackPupupMenuEx 前安装WH_MSGFILTER 钩子,代码如下:m_hMsgHook=SetWindowsHookEx(WH_MSGFILTER,MessageProc,0,GetCurrentThreadId();MssageProc 是钩子函数,代码如下:LRESULTCALLBACKMessageProc(int code,WPARAMwParam,LPARAMlParam)if(code=MSGF_MENU)HookMessageProc(lParam);return CallNextHookEx(m_hMsgHook,code,wParam,l

38、Param);函数检查消息,如果是来自菜单,则将消息传递给函数 HookMessageProc 处理,我们所要做的就是在该函数中检测消息 WM_MOUSEMOVE,并测试鼠标位置,如果鼠标已经移动到另一个按钮上,则关闭菜单并显示下一个菜单,关闭菜单使用消息 WM_CANCELMODE,当菜单关闭后,我们要释放钩子,在下一个菜单弹出时重新安装钩子,弹出菜单示例代码如下:void TrackPopup(HWND hWndToolBar,int iButton)while(iButton=0)SendMessage(hWndToolBar,TB_SETHOTITEM,iButton,0);iPopu

39、p=iButton;/安装钩子g_hMsgHook=SetWindowsHookEx(WH_MSGFILTER,MessageProc,0,GetCurrentThreadId();/弹出菜单TrackPopupMenuEx();/卸载钩子UnhookWindowsHookEx(g_hMsgHook);iButton=iNextPop;/下一个弹出项,若为负,则退出SendMessage(hWndToolBar,TB_SETHOTITEM,-1,0);(经验与建议:如果 button 使用样式 TBSTYLE_DROPDOWN,请不要在消息 TBN_DROPDOWN 中直接调用该函数,应使用中

40、间消息,然后使用 PostMessa 个发送该消息,以使 TBN_DROPDOWN可以直接返回,否则消除第一个高亮热点是很麻烦的事。)iPopup为当前弹出项,iNextPop为下一个弹出项,这些变量需要在函数 HookMessageProc 中处理,示例代码如下:void HookMessageProc(MSG*pMsg)if(pMsg-message=WM_MOUSEMOVE)int iButton,iCount;POINTpt=LOWORD(pMsg-lParam),HIWORD(pMsg-lParam);ScreenToClient(hWndToolbar,&pt);iButton=S

41、endMessage(hWndToolbar,TB_HITTEST,0,&pt);iCount=SendMessage(hWndToolbar,TB_BUTTONCOUNT,0,0);if(iPopup!=iButton&iButton=0)iNextPop=iButton;SendMessage(hWndMain,WM_CANCELMODE,0,0);(经验与建议:不要试图在此处调用 TrackPopup,我曾试图取消该函数内的 while 循环,直接在此调用该函数,结果是在 TrackPopupMenuEx 未返回之前,该函数已被调用)elseiNextPop=-1;这里,仅仅处理了鼠标移

42、动消息,真正的菜单还应处理键盘导航消息,详细的代码可以参考BCGControlBar(http:/ SizableRebar(http:/ API函数可以参考 msdn。Msdn上相关资料:http:/ 定制窗口的方法定制窗口的方法VC+6.0 是 Microsoft 新近推出的可视化 C+集成开发环境。它在继承以前 VC+的基础上增加了许多新的功能,用于支持 Win32 平台应用程序、服务程序和控件的开发。VC+5.0 提供了强大、快捷的编程工具,其中最基本的是三个导航:AppWizard 用于程序框 架的生成,AppStudio 用于资源的编辑,ClassWizard用于类的编辑和管理。其

43、中,窗口、菜单等无需用户编写程序,而由系统自动生成。但在许多情况下,用户要设置自己希 望的窗口(即定制窗口)。一、如何在多文档界面下去掉开始的子窗口在多文档界面下,自动生成一个新的子窗口,而一个实际的应用系统往往是由用户操作后再生成新的窗口。为了去掉开始的子窗口,可在应用程序文件分析命令行的语句CcommandLineInfo cmdInfo;ParseCommandLine(cmdInfo);后加入:cmdInfo.m_nShellCommand=CcommandLineInfo:FileNothing;去掉子窗口后,就只剩下主框架窗口了。因为在多文档界面中,系统生成两个菜单:一个是用户的菜

44、单,另一个是系统主框架菜单。通常用户工作在用户菜单。为了保证菜 单界面不变,可修改主框架菜单资源,使其与用户菜单保持一致。二、修改窗口标题栏在缺省情况下,窗口标题栏中显示的文档名为文件名。若要在标题栏显示一个长字符串,而又不修改文件名,则可将项目工作区转换到 Resource View 面版,选择串表(StringTable)资源,在StringTable 中双击 IDR-MAIN-FRAME 项,caption 中显示一字符串 xxnyy.,将第一个参数修改为用户自己希望见到的主窗口标题即可。三、修改主框架窗口、子窗口及其显示性质可通过覆盖 CWnd 的成员函数 PreCreateWindo

45、w 来修改主窗口和子窗口。PreCreateWindow 函数在即将创建窗口前被调用,函数原型为:Virtual BOOLPreCreateWindow 函数(CREATESTRUCTcs)。如果要覆盖 PreCreateWindow 函数,则在创建窗口前可以修改 CREATESTRUCT 结构以替换缺省参数。CREATESTRUCT结构存放窗口特征,如窗口坐标、风格等,还可以定义新窗口风格。若想修改主框架窗口,则可以在 MainFrm.cpp 的下列成员函数中加入待修改的内容。例如:BOOLCmainFrame:PreCreateWindow(CREATESTRUCT&cs)/通过修改 CR

46、EATESTRUCT 结构来修改窗口类或风格/定义新窗口的高度、宽度cs.cx=450;cs.cy=300;/定义新窗口风格为去掉主窗口名及最大化等按钮cs.style=ws-POPWINDO;return CframeWnd:PreCreateWindow(cs);定制子窗口的操作与上述主窗口相同,可在 ChildFrm.cpp中加入以下内容:BOOLCmainFrame:PreCreateWindow(CREATESTRUCT&cs)/通过修改 CREATESTRUCT 结构来修改窗口类或风格return C mdichildWnd:PreCreateWindow(cs);要修改视图窗口的

47、显示性质,则可在视图文件 xxView.cpp 的下述成员函数中加入以下语句:BOOLxxView:PreCreateWindow(CREATESTRUCT&cs)/增加的语句cs.lpszClass=AfxRegisterWndClass(cs-HREDRAW|CS-VREDRAW,0,(HBRUSH):GetStockObject(WHITE-BRUSH),0);return CscrollView:PreCreateWindow(cs);其中,cs 的参数 pszClass 用于存放 Windows窗口类名称。要想注册 Windows 窗口类,则必须调用全局函数 AfxRegisterW

48、ndClass。该函数原型为:LPCTSTRAFXAPIAfxRegisterWndClass(UINTnClassStyle,HCURSOR hCursor=0,HBRUSH hbrBackground=0,HICONhIcon=0)上述各参数用于定义风格,其含义分别为光标资源句柄、背景资源句柄、图标资源句柄。上述增加的语句的作用是:改变窗口大小时重画窗口、不显示光标图标、设置白色 背景。四、窗口的滚动使用 CscrollView 代替 Cview 类即可实现滚动窗口。此时,系统生成 OnInitialUpdate()成员函数:void CmyscrollView:OnInitialUpda

49、t()CscrollView:OnIntialUpdate();Csize sizeTotal;SizeTotal.cs=sizeToal.cy=100;SetScrollSizes(MM-TEXT,sizeTotal);其中,cs 和 cy 分别为滚动窗口的水平、垂直分量,表明窗口的水平、垂直方向尺寸小于 100 像素单位时将出现水平方向滚动条和垂直方向滚动条。通过修改滚动尺寸,可改变 出现滚动条的最小窗口。例如,若“sizeTotal.cx=600;sizeTotal.cy=800;”,则当窗 口尺寸小于 600*800 时,就会出现滚动条。五、窗口分割该功能可将窗口分割成多个可滚动的面板

50、,面板之间的边界称为分割条,可用分割条来调整每个面板的相对大小。要想增加窗口分割功能,则必须修改主窗口类。首先,在 主窗口类的头文件MainFrm.h 中添加以下代码:CsplitterWnd m-SWnd;Virtual BOOLOnCreateClient(LPCREATESTRUCTcs,CcreateContext*pContext);再在 MainFrm.cpp 中添加成员函数 OnCreateClient 的定义:BOOLCmainFrame:OnCreateCline(LPCREATESTRUCTcs,CcreateContext*p Context)return m-SWnd.

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 技术资料 > 其他杂项

本站为文档C TO C交易模式,本站只提供存储空间、用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。本站仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知淘文阁网,我们立即给予删除!客服QQ:136780468 微信:18945177775 电话:18904686070

工信部备案号:黑ICP备15003705号© 2020-2023 www.taowenge.com 淘文阁