MFC 窗口位置管理详细分析及实例
在一般用 MFC 编写的程序的窗口客户区中,可能有好几个子窗口(具有 WM_CHILD 风格的窗口)。上边是
工具栏,中间是视图窗口,下边是状态栏。三个窗口在框架的客户区里和平共处,互不重叠。主框架窗口
的尺寸改变了,别的子窗口都能及时调整自己的尺寸以便保持相互位置关系不变,例如状态条窗口总能保
持在主框架客户区底部,并且其宽度总能和主框架客户区宽度一致。工具栏窗口总能停靠在主框架的某一
边不变,其宽度或高度总能和主框架客户区的宽度或高度一致,视图窗口总能填满主框架客户区的剩余空
间。
假如我们自己从 CWnd 类派生一个窗口类并生成一个窗口,在它的客户区里要生成若干个子窗口,我们想
使这些子窗口排列得规规矩矩,互不重叠,当父窗口的尺寸变了时各个子窗口能适时调整自己的尺寸和位
置,使各个子窗口之间的位置大小比例关系不变。当移动其中一个或几个子窗口时,别的子窗口能及时为
这个移动了的子窗口让位。当然我们可以利用 api 函数里管理窗口的函数来编写自己的管理子窗口的方法。
可是如果在父窗口的客户区里有了工具栏,状态条等等子窗口时,你自己加进来的子窗口还能和这些 mfc
提供的子窗口融洽相处吗?你如何保证你的子窗口不会覆盖了能够四处停靠的工具栏?当工具栏和状态条
消失后你的子窗口如何才能知道,以便及时调整自己的大小从而覆盖工具栏和状态条腾出的空间?基于文
档视图构架的窗口的客户区内还有个视图,你自己硬加上的子窗口能不和视图窗口争地盘吗?
所以必须了解 mfc 的窗口管理它的客户区的方法。其实,mfc 的窗口管理它的客户区的方法是非常简单的:
父窗口调用一个函数,子窗口响应一个消息,就这么多。
CWnd::RepositionBars 函数和 WM_SIZEPARENT 消息
先简述一下 mfc 的窗口为子窗口分配客户区空间的过程:这一过程是父窗口与子窗口共同协调完成的。父
窗口先提供它的客户区内的一块区域,叫做起始可用区域。然后调用一个函数,在这个函数里,父窗口把
这片区域通过一个消息提交给它的第一个子窗口,该子窗口决定自己要占用多大一块,然后在可用区域里
把它将占据的部分划出去,这样可用区域就被切去了一块。父窗口再把这块剩下的可用区域通过同样的消
息提交给第二个子窗口,第二个子窗口再根据自己的需要切掉一块。如此这般,每个子窗口都切去自己所
需的一块。最后剩下的可用区域就给最后的子窗口使用。可以看出,除了最后一个子窗口外,其它子窗口
都得在消息响应函数里有自己的算法来决定自己将在可用区域里占据多大一块,最后一个子窗口由于别无
选择,所以不需要这样的算法。
当然,初始的可用区域是一个矩形,每次被切割后剩下的可用区域还是一个矩形,不可能是别的形状的。
举例说来,在一个典型单文档程序中,父窗口就是从 CFrameWnd 派生的主框架窗口,最后一个子窗口就
是视图窗口,如果用了 CSplitterWnd 生成分隔条的话,最后一个子窗口就是拥有分隔条的那个窗口。其它
子窗口就是工具栏窗口和状态条窗口,以及可能有的别的控件窗口。
在典型多文档界面程序中,父窗口就是主框架窗口,最后一个子窗口就是覆盖在主窗口客户区,背景为黑
灰色,拥有包含文档的子框架窗口的那个窗口,这是个预定义了窗口类的窗口,它的窗口类名是
“MDIClient”。如果用了 CSplitterWnd 生成分隔条的话,最后一个子窗口就是拥有分隔条的那个窗口。其它
窗口就是工具栏窗口,状态条窗口以及可能有的别的控件窗口。
这个函数和消息是:函数 CWnd::RepositionBars()以及消息 WM_SIZEPARENT。这个消息是 mfc 自定义的,