RepositionBars的用法和参数的意义(引用别人的)

MFC窗口位置管理详细分析及实例 在一般用MFC编写的程序的窗口客户区中,可能有好几个子窗口(具有WM_CHILD风格的窗口)。上边是工具栏,中间是视图窗口,下边是状态栏。三个窗 口在框架的客户区里和平共处,互不重叠。主框架窗口的尺寸改变了,别的子窗口都能及时调整自己的尺寸以便保持相互位置关系不变,例如状态条窗口总能保持在 主框架客户区底部,并且其宽度总能和主框架客户区宽度一致。工具栏窗口总能停靠在主框架的某一边不变,其宽度或高度总能和主框架客户区的宽度或高度一致, 视图窗口总能填满主框架客户区的剩余空间。

假如我们自己从CWnd类派生一个窗口类并生成一个窗口,在它的客户区里要生成若干个子窗口,我们想使这些子窗口排列得规规矩矩,互不重叠,当父窗 口的尺寸变了时各个子窗口能适时调整自己的尺寸和位置,使各个子窗口之间的位置大小比例关系不变。当移动其中一个或几个子窗口时,别的子窗口能及时为这个 移动了的子窗口让位。当然我们可以利用api函数里管理窗口的函数来编写自己的管理子窗口的方法。可是如果在父窗口的客户区里有了工具栏,状态条等等子窗 口时,你自己加进来的子窗口还能和这些mfc提供的子窗口融洽相处吗?你如何保证你的子窗口不会覆盖了能够四处停靠的工具栏?当工具栏和状态条消失后你的 子窗口如何才能知道,以便及时调整自己的大小从而覆盖工具栏和状态条腾出的空间?基于文档视图构架的窗口的客户区内还有个视图,你自己硬加上的子窗口能不 和视图窗口争地盘吗?

所以必须了解mfc的窗口管理它的客户区的方法。其实,mfc的窗口管理它的客户区的方法是非常简单的:父窗口调用一个函数,子窗口响应一个消息,就这么多。

CWnd::RepositionBars函数和WM_SIZEPARENT消息

先简述一下mfc的窗口为子窗口分配客户区空间的过程:这一过程是父窗口与子窗口共同协调完成的。父窗口先提供它的客户区内的一块区域,叫做起始可 用区域。然后调用一个函数,在这个函数里,父窗口把这片区域通过一个消息提交给它的第一个子窗口,该子窗口决定自己要占用多大一块,然后在可用区域里把它 将占据的部分划出去,这样可用区域就被切去了一块。父窗口再把这块剩下的可用区域通过同样的消息提交给第二个子窗口,第二个子窗口再根据自己的需要切掉一 块。如此这般,每个子窗口都切去自己所需的一块。最后剩下的可用区域就给最后的子窗口使用。可以看出,除了最后一个子窗口外,其它子窗口都得在消息响应函 数里有自己的算法来决定自己将在可用区域里占据多大一块,最后一个子窗口由于别无选择,所以不需要这样的算法。

当然,初始的可用区域是一个矩形,每次被切割后剩下的可用区域还是一个矩形,不可能是别的形状的。

举例说来,在一个典型单文档程序中,父窗口就是从CFrameWnd派生的主框架窗口,最后一个子窗口就是视图窗口,如果用了 CSplitterWnd生成分隔条的话,最后一个子窗口就是拥有分隔条的那个窗口。其它子窗口就是工具栏窗口和状态条窗口,以及可能有的别的控件窗口。

在典型多文档界面程序中,父窗口就是主框架窗口,最后一个子窗口就是覆盖在主窗口客户区,背景为黑灰色,拥有包含文档的子框架窗口的那个窗口,这是 个预定义了窗口类的窗口,它的窗口类名是“MDIClient”。如果用了CSplitterWnd生成分隔条的话,最后一个子窗口就是拥有分隔条的那个 窗口。其它窗口就是工具栏窗口,状态条窗口以及可能有的别的控件窗口。

这个函数和消息是:函数CWnd::RepositionBars()以及消息WM_SIZEPARENT。这个消息是mfc自定义的,不是windows自有的。

先简单说明一下这个函数和消息。

1。函数CWnd::RepositionBars()

这个函数不是虚函数,所以就无法在派生类里通过覆盖来编制自己的版本了,只能搞懂它的功能,以便能灵活使用。

简单而言,这个函数的功能是将可用的客户区区域信息放到消息WM_SIZEPARENT的消息参数里,然后枚举本窗口的所有子窗口,给每个子窗口 (除掉一个特定的子窗口,相当于上文提到的最后一个子窗口)都发送这个消息,每个响应这个消息的子窗口都会把可用客户区切去一块。最后把那个特定的子窗口 的尺寸和位置调整到刚好放在最后剩下的可用区域里。

2。消息WM_SIZEPARENT

每个欲参与分配客户区的子窗口都要响应这个消息,除非这个子窗口是那个特定的子窗口。

响应这个消息的子窗口至少要做两件事:1,将可用的父窗口客户区切去自己所占据的一块。2,根据消息参数的指示,将自己的大小和位置调整到刚好容纳到自己所占据的区域里或不做调整。

下面详细介绍一下函数CWnd::RepositionBars()和消息WM_SIZEPARENT。

1。函数CWnd::RepositionBars() void RepositionBars( UINT nIDFirst, UINT nIDLast, UINT nIDLeftOver, UINT nFlag = CWnd::reposDefault, LPRECT lpRectParam = NULL, LPCRECT lpRectClient = NULL, BOOL bStretch = TRUE );

参数比较多,但还是比较好懂的。

(1)nIDFirst和nIDLast

参与分配父窗口客户区的子窗口的id范围。

每个WM_CHILD风格的窗口都有个id,这是在窗口创建过程中指定的。函数CWnd::Create()的第六个参数就是这个id。api函数 CreateWindow和 CreateWindowEx里的那个HMENU类型的参数,当窗口的风格里有WM_CHILD时,它不是指的菜单句柄,而是该窗口的id。

nIDFirst和nIDLast参数指明了:如果一个子窗口的id值大于等于nIDFirst并且小于等于nIDLast,在这个函数中才会给这个子窗口发送 WM_SIZEPARENT消息,这个子窗口才能参与父窗口客户区的分配。

(2)nIDLeftOver

前面说过,有一个特定的子窗口,它不响应WM_SIZEPARENT消息。只有当其它的子窗口都分配完了,它才来捡取父窗口客户区里剩下的那块。 nIDLeftOver正是这个子窗口的id。它也必须大于等于nIDFirst并且小于等于nIDLast。

(3)lpRectClient

这是一个指向RECT结构数据的指针。这个RECT结构里存放的正是父窗口客户区的初始可用区域。随着在该函数里依次给各个子窗口发送 WM_SIZEPARENT消息,每个响应这个消息的子窗口都会切去自己所占据的部分。最后剩下的部分,就是id为nIDLeftOver的子窗口将要占 据的区域了。这个参数可以为NULL,这时初始的可用区域就是整个父窗口客户区。

(4)nFlag和lpRectParam

这两个参数放在一起讲比较好。nFlag是该函数的功能标志,它可以有三个值:reposDefault,reposQuery 和reposExtra。

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

当nFlag等于reposQuery 时,RepositionBars函数的功能是这样的:依次给id介于nIDFirst和nIDLast之间并且不等于nIDLeftOver的子窗口发 送WM_SIZEPARENT消息,每个响应这个消息的子窗口从lpRectClient所指的结构里切去自己所占据的部分,但是他们并不调整自己的大小 和位置,最后RepositionBars函数并不调整将id为nIDLeftOver的子窗口的大小和位置,而是根据bStretch的值来做动作:如 果bStretch为TRUE,那么 RepositionBars函数把最后剩下的可用区域拷贝到lpRectParam指向的RECT结构里;如果bStretch为FALSE,那么 RepositionBars函数把所有其他子窗口占用掉的可用区域的高和宽(要所有的子窗口都紧排在一起,形成一个大的矩形,这个值才有意义)拷贝到 lpRectParam指向的RECT结构的bottom 和right成员里,其top和left成员被置零。使用这个nFlag值来调用RepositionBars的目的不是要重排子窗口,而是要看看,假如 重排子窗口的话,这些子窗口将占去多大一块,最后剩下的可用区域在什么位置等等信息。

当nFlag等于reposExtra时,该函数的功能和nFlag等于reposDefault时差不多,有点小小的区别。此时需要用到 lpRectParam。前面说过,当 nFlag等于reposDefault时,RepositionBars函数将在最后把id为nIDLeftOver的子窗口的大小和位置调整到被其他 子窗口切剩的可用区域内,使这个子窗口正好完全覆盖最后的可用区域。而当nFlag等于reposExtra时,RepositionBars在调整id 为nIDLeftOver的子窗口的大小和位置前,还要用 lpRectParam来对最后剩下的可用区域做修正。假设lpRect指向的是最后的可用区域,那么这个修正是这样进行的:

lpRect->top+=lpRectParam->top;
lprect->left+=lpRectParam->left;
lpRect->right-=lpRectParam->right;
lpRect->bottom-=lpRectParam->bottom;

通过这样的修正,可以使最后剩下的可用区域不被id为nIDLeftOver的子窗口占满,而是空出一些地方来留作他用。
(5)bStretch

这个参数上面已经提到一点它的作用。它主要是提供给各个响应WM_SIZEPARENT消息的子窗口用的,子窗口例如工具栏,状态条等在决定自己将
从父窗口客户区的可用空间里划走多少时,这个参数也是个判断的依据。详细可以参阅工具栏和状态条响应WM_SIZEPARENT的函数
OnSizeParent()。

RepositionBars的用法和参数的意义(引用别人的)

时间: 2024-11-08 22:02:23

RepositionBars的用法和参数的意义(引用别人的)的相关文章

java 方法参数-值调用,引用调用问题

(博客内容来自于core java卷一) 1. xx调用:程序设计语言中方法参数的传递方式: 引用调用(call by reference):表示方法接收的是调用者提供的变量地址. 值调用(call by value):表示方法接收的是调用者提供的值. 命名调用(call by name):已经成为历史. 2. Java使用值调用,而且只有值调用.也就是说方法得到的是参数值的一个拷贝,并不是参数值本身,所以,方法不能修改传递给它的的任何参数变量本身. 看下面代码: public class te

CATransform3D参数的意义

经常忘记CATransform3D各参数的意思,记下来好好理解下 struct CATransform3D { CGFloat m11(x缩放),m12(y切变),m13(旋转),m14(); CGFloat m21(x切变),m22(y缩放),m23(),m24(); CGFloat m31(旋转),m32(),m33(),m34(透视效果,要操作的这个对象要有旋转的角度,否则没有效果.正直/负值都有意义); CGFloat m41(x平移),m42(y平移),m43(z平移),m44();

JMeter学习-011-JMeter 后置处理器实例之 - 正则表达式提取器(三)多参数获取进阶引用篇

前两篇文章分表讲述了 后置处理器 - 正则表达式提取器概述及简单实例.多参数获取,相应博文敬请参阅 简单实例.多参数获取. 此文主要讲述如何引用正则表达式提取器获取的数据信息.其实,正则表达式提取器获取的数据,均可看做一个变量(单个数据,此处指所需获取的测试相关数据)或数组(多个数据),通过引用变量或者数组的数据,达到应用其数据的目的.下面针对此两种方式进行介绍. 第一种:单数据变量 但数据变量的应用比较简单,同我们日常 shell 脚本引用变量相同,引用样式:引用名称.例如要引用下图中的变量,

C++ 为什么拷贝构造函数参数必须为引用?赋值构造函数参数也必须为引用吗?

之前写拷贝构造函数的时候,以为参数为引用,不为值传递,仅仅是为了减少一次内存拷贝.然而今天看到一篇文章发现自己对拷贝构造的参数理解有误. 参数为引用,不为值传递是为了防止拷贝构造函数的无限递归,最终导致栈溢出. 下面来看一个例子: class test { public: test() { cout << "constructor with argument\n"; } ~test() { } test(test& t) { cout << "

Swift 2.0学习笔记(Day 20)——函数中参数的传递引用

原创文章,欢迎转载.转载请注明:关东升的博客 参数的传递引用 类是引用类型,其他的数据类型如整型.浮点型.布尔型.字符.字符串.元组.集合.枚举和结构体全部是值类型. 有的时候就是要将一个值类型参数以引用方式传递,这也是可以实现的,Swift提供的inout关键字就可以实现.看下面的一个示例: func increment(inout value:Double, amount:Double = 1.0) { value += amount } var value : Double = 10.0

TOP命令各个参数代表意义详解

TOP命令各个参数代表意义详解 Top命令是Linux下常用的系统性能分析工具,能实时查看系统中各个进程资源占用情况. 第一行分别显示: 当前时间.系统启动时间.当前系统登录用户数目.平均负载(1分钟,10分钟,15分钟). 平均负载(load average),一般对于单个cpu来说,负载在0-1.00之间是正常的,超过1.00须引起注意.在多核cpu中,系统平均负载不应该高于cpu核心的总数. 第二行分别显示: 进程总数.运行进程数.休眠进程数.终止进程数.僵死进程数. 第三行: %us用户

零基础学python-17.2 参数与共享引用

这一章节我们来讨论一下参数与共享引用 承接上一章节所说的参数的传递是通过自动将对象赋值给本地变量名来实现的,其本质就是复制引用,传递对象 1.我们下面以传递不可变对象为例子: >>> b=1 >>> def test(x): print(x) print(id(x)) x=2 print(x) print(id(x)) >>> test(b) 1 497734096 2 497734112 >>> 从代码可以看出,传递过程中x赋值了1

为什么赋值操作符函数的参数为const引用,返回值为引用

为什么赋值操作符函数的参数为const引用,返回值为引用 1.返回值类型 返回类型一般声明为类型的引用,并在函数结尾时返回实例自身的引用(即*this).这里主要有两个原因:(1)返回引用可以减少一次拷贝构造和析构函数导致不必要的开销,因为返回值类型不是引用,会创建一个匿名对象,这个匿名对象时个右值,获取return的值.(2)可以实现连续赋值 在例子中 b=c=a; 返回值不是引用类型也是可以的,其运算顺序 b=(c=a); c得到一个右值,再将右值赋给b,所以逻辑上没有问题的.但是如果是 (

《从零开始学Swift》学习笔记(Day 20)——函数中参数的传递引用

原创文章,欢迎转载.转载请注明:关东升的博客 参数的传递引用 类是引用类型,其他的数据类型如整型.浮点型.布尔型.字符.字符串.元组.集合.枚举和结构体全部是值类型. 有的时候就是要将一个值类型参数以引用方式传递,这也是可以实现的,Swift提供的inout关键字就可以实现.看下面的一个示例: func increment(inoutvalue:Double, amount:Double = 1.0) {     value += amount }   var value : Double =