MFC控制条窗口布局原理

MFC 窗口分割功能深入源码解析 类位于MFC(Microsoft Foundation Classes)库中,它用于创建和管理可分割的窗口。继承自CWnd类,这意味着它拥有窗口的大部分基本功能。但类还有一些特殊的功能,专门用于处理分割窗口的行为。在继承层次中,通过CWnd间接继承自CObject,这是所有MFC类的根类。CObject提供了序列化、诊断、运行时类型信息等基础服务,使得类能够执行一些更高级的操作。 阅读详情
  MFC 控制条窗口布局原理

——by Koote Bi@fudan cse
一、框架窗口
框架窗口在其大小被改变的时候会收到 WM_SIZE 消息,这个消息的处理函数是 CFrameWnd::OnSize ,此函数接着调用 RecalcLayout 来重新安置各子窗口,它的主体代码如下:
if(GetStyle() & FWS_SNAPTOBARS)
{
CRect rect(0, 0, 32767, 32767);
RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposQuery, &rect, &rect, FALSE);
RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra, &m_rectBorder, &rect, TRUE);
CalcWindowRect(&rect);
SetWindowPos(NULL,0,0,rect.Width(),rect.Height(),SWP_NOACTIVATE|SWP_NOMOVE|SWP_NOZORDER);
}
else
{
        RepositionBars(0, 0xffff, AFX_IDW_PANE_FIRST, reposExtra, &m_rectBorder);
}
这里有两个小的地方要注意,第一是 FWS_SNAPTOBARS 风格。一般来说,都是框架窗口主动改变大小,子窗口随之要修改自己来适应框架窗口的改变,但是这个 FWS_SNAPTOBARS 风格却相反,是让框架窗口改变大小来适应它的子窗口,但我一路跟踪下来没有发现有哪个框架窗口有这个风格,都是走 else 分支的(事实上这个风格是为 CMiniDockFrameWnd 准备的,这个框架窗口的大小是根据它内部的控制条来定的);第二是要注意 RecalcLayout 是不可重入的, MFC 防止重入的方法虽然非常的简单有效,但是它的方法要不能防止多线程的重入 —— 话说回来 MFC 本身就不是一个线程安全的库 J
好了现在我们进入了整个重布局动作的主体函数 RepositionBars ,让我们仔细分析一下它都干了些啥见不得人的 “ 勾当 ” (这个函数在 MSDN 里有文档记载,关于它的几个参数的含义就不在这里赘述了):
首先,它创建一个 AFX_SIZEPARENTPARAMS 结构,并填写好它的成员变量,最主要的就是两个: bStretch 和 rect ,前一个是 BOOL 型变量,表明子窗口是否需要拉伸(拉伸到和客户区同宽或同高),后一个是当前客户区大小。
接着,框架窗口按照 Z-order ,从最上面的子窗口开始,依次向它的所有子窗口发送 WM_SIZEPARENT 消息( ID 为 nIDLeftOver 的子窗口除外),以通知它们,按照新的客户区,重新计算自己的大小和位置,并从 AFX_SIZEPARENTPARAMS::rect 中将自己所占的那一块 rectangle 扣除,这样所有的子窗口计算完毕后框架窗口就可以知道剩余客户区的大小( PS :到底都发送给了谁?又是按照什么次序?以 MDIDemo 为例,该例子创建了一个 CToolBar 、一个 CThumbnailListCtrlBar ,在都是 Dock 状态下,跟踪记录下的所发送的窗口的 ID ,依次是 0xE801 à 0xE81B à 0xE81E à 0xE81C à 0xE81D ,察看各子窗口 ID 的定义得知次序是状态栏 à 上方的 Dock Bar à 下方的 Dock Bar à 左边的 Dock Bar à 右边的 Dock Bar ,这里要注意的是,所找到的第一个子窗口的 ID 是 0xE900 ( 0xE900 被定义成 AFX_IDW_PANE_FIRST ,在这个例子里它是 View 的窗口 ID ,与这个 ID 对应的还有另一个 ID 叫 AFX_IDW_PANE_LAST , SDI 的 View 窗口, MDI 的 MDIClient 窗口,分隔条窗口等的 ID 都要介于上面两个 ID 值之间),等于 nIDLeftOver ,所以 WM_SIZEPARENT 消息是不发给它的。那么为什么 Tool bar 和 Thumbnail bar 也收不到消息呢?因为 Dock Bar 是它的父窗口,消息发给 Dock Bar 了, Dock bar 会计算它内部停靠的全部子窗口的大小,就不需要框架窗口操心了,除此之外,浮动的控制条也是不接受 WM_SIZEPARENT 消息的,原因很简单,浮动的控制条不会跟随主框架窗口的大小改变而改变)。
发送完毕之后(这里有个细节,框架窗口发送 WM_SIZEPARENT 消息用的是 SendMessage ,这意味着只有子窗口处理完该消息后, SendMessage 才返回,框架窗口才会接着发送消息给下一个子窗口,全部发送完毕也就意味了所有的子窗口都已经从 AFX_SIZEPARENTPARAMS::rect 中把自己要的那一块 rectangle 给拿掉了),剩下的就是最后可用的客户区了,根据 nFlags 的值,执行不同的返回动作。其中 reposQuery 表示只查询,不做实际的重布局动作,把最后剩下的客户区,拷贝到 lpRectParam 就返回了,如果不是 reposQuery 那就要做重布局了,对 reposDefault ,我们要把 ID 为 nIDLeftOver 的子窗口的大小和位置调整到被其他子窗口切剩后剩下的可用客户区内,使这个子窗口正好完全覆盖最后的可用区域(也就是说所有的子窗口把客户区全部挤满了)。而当 nFlag 等于 reposExtra 时,在调整 nIDLeftOver 子窗口的大小和位置前,用 lpRectParam 来对最后剩下的可用区域做修正,具体来说就是把 AFX_SIZEPARENTPARAMS::rect 向里缩,缩的距离由 lpRectParam 指定,这样就使最后剩下的客户区不被 nIDLeftOver 子窗口占满,而是空出一些地方。修正完毕后最后一次性重布局所有的子窗口。
至此,框架窗口所做的动作全部完成。
 
二、控制条子窗口
分析完了框架窗口,接着分析控制条这边所要做的响应动作。根据前面的跟踪我们知道除了 CStatusBar 和 CDockBar ,从 CControlBar 继承下来的控制条诸如 CToolBar 、 CDialogBar 等,是收不到 WM_SIZEPARENT 消息的,它们的父窗口 CDockBar 代替它们接收这个消息。因此整个重布局过程的起点是 CDockBar 对 WM_SIZEPARENT 消息的处理函数 CDockBar::OnSizeParent (对 CStatusBar 而言,其起点是 CControlBar::OnSizeParent ,这里不打算对它作进一步分析,有兴趣可以自己完成)。第一步让我们来分析这个函数所做的动作,这个函数不长,把完整代码列出:
LRESULT CDockBar::OnSizeParent(WPARAM wParam, LPARAM lParam)
{
AFX_SIZEPARENTPARAMS* lpLayout = (AFX_SIZEPARENTPARAMS*)lParam;
 
// set m_bLayoutQuery to TRUE if lpLayout->hDWP == NULL
BOOL bLayoutQuery = m_bLayoutQuery;
CRect rectLayout = m_rectLayout;
 
m_bLayoutQuery = (lpLayout->hDWP == NULL);
m_rectLayout = lpLayout->rect;
LRESULT lResult = CControlBar::OnSizeParent(wParam, lParam);
 
// restore m_bLayoutQuery
m_bLayoutQuery = bLayoutQuery;
m_rectLayout = rectLayout;
 
return lResult;
}
如前所述, WM_SIZEPARENT 消息传递一个 AFX_SIZEPARENTPARAMS 结构体的指针作为参数,在这里我们先取出这个结构体,然后判断 AFX_SIZEPARENTPARAMS::hDWP 是否为空,是的话说明父窗口仅仅是想查询 ,并不要真的进行重布局动作(回到 RepositionBars ,当 nFlags 为 reposQuery 时,并不调用 BeginDeferWindowPos ,故而 AFX_SIZEPARENTPARAMS::hDWP 就一定是 NULL ) ,完成必要的变量保护后,进入父类 CControlBar 的 OnSizeParent ,在此,根据控制条窗口的风格,决定如何计算控制条的尺寸,具体是这样的;
        DWORD dwMode = lpLayout->bStretch ? LM_STRETCH : 0; // 拉伸否 ?
        if((m_dwStyle & CBRS_SIZE_DYNAMIC) && m_dwStyle & CBRS_FLOATING) // 浮动 , 形状可变
        {
               dwMode |= LM_HORZ | LM_MRUWIDTH;// 计算水平状态常用尺寸
        }
        else if(dwStyle & CBRS_ORIENT_HORZ) // 水平停靠
        {
               dwMode |= LM_HORZ | LM_HORZDOCK;// 计算水平停靠状态尺寸
        }
        else
        {
               dwMode |= LM_VERTDOCK; // 计算垂直停靠状态尺寸
        }
        CSize size = CalcDynamicLayout(-1, dwMode);
要注意的是最后一行调用, CalcDynamicLayout ,这个函数是一个虚函数,先被调用的是 CControlBar:: CalcDynamicLayout ,这个函数调用了 CalcFixedLayout (也是一个虚函数),注意到 CDockBar 对此函数进行了重载,所以转了一圈我们又回到了 CDockBar 中。
 

您认为本文应该得        共有2人参与打分打印|收藏|讨论|投诉

暂无图片

欲将心事付瑶琴,知音少,弦断有谁听?

MFC单文档界面窗口任意分割技术实战指南 是一个用于在 MFC 应用程序中创建分割窗口的类。分割窗口允许用户通过拖动分割条来调整各个子窗口的大小。MFC 提供了几个类,可以帮助我们快速实现窗口的分割功能,而正是实现这一功能的核心类。如果默认的分割窗口布局不能满足需求,可以通过继承类并重写相关函数来实现自定义的布局。例如:public:// 自定义创建视图的函数// 这里可以添加自定义的创建逻辑除了通用的窗口状态外,可能还需要保存一些自定义的状态信息。例如,用户在某个特定视图中的搜索条件、过滤设置或者特殊的布局安排等。 阅读详情

相关推荐

MFC界面编程布局管理

很好的布局管理!MFC界面编程的好帮手,直接加入工程就可用!

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

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

huoyunka的专栏 1万+

MFC布局管理,模仿Winform布局控件

仿C#的TableLayoutPanel封装的MFC布局管理类,方便MFC界面控件布局,刚学MFC时做的,不是很全,只可以作为参考

CWnd::RepositionBars函数和WM_SIZEPARENT消息

<br />转帖自: http://hi.baidu.com/shi51314/blog/item/d5646409199951a82fddd426.html<br /> <br /> <br />在一般用MFC编写的程序的窗口客户区中,可能有好几个子窗口(具有WM_CHILD风格的窗口)。 <br />上边是工具栏,中间是视图窗口,下边是状态栏。三个窗口在框架的客户区里和平共处,互 <br />不重叠。主框架窗口的尺寸改变了,别的子窗口都能及时调整自己的尺寸以便保持相互位置 <br />关系不变,例如状态

秋城 4130

MFC界面自动布局demo

使用easysize精巧类实现MFC界面布局layout,easysize类中使用宏定义实现,使用方法非常简单容易,帮助你轻松实现MFC界面自动布局

mfc 各种控件的使用和布局(透明vista风格)

如果您对mfc的界面美化存有疑虑,或者不知道怎样做更符合您的要求,请看该代码,自己收集整合的,非常漂亮

【MFC】如何手动发送WM_SIZE系统消息

WM_SIZE作为系统的一个内置的核心消息,他是如何运作的呢? 通过本篇源码的解析 可以清楚的了解MFC内部消息的流向,这是作为C语言程序员理应了解的东西,以此消息为实例,我们便可以清楚的知道其他系统消息是如何运作的,对于MFC原理的了解以及灵活的实际应用来说有重大意义。

蒙蒙plus 3612

ST7789T3与CST816D驱动全解析,面试技巧第11篇:嵌入式面试场景问答 10 连发。

SPI模式下,SCLK、MOSI、CS、DC、RST为必需引脚;8080模式下需连接D0-D7、WR、RD等信号线。CST816D触摸芯片通常通过I2C接口通信,需连接SCL、SDA及INT(中断)引脚。确保电源引脚(VCC、GND)稳定供电,ST7789T3典型工作电压为3.3V。显示异常时检查时序参数,如SPI时钟频率(建议≤40MHz)、数据建立时间。初始化流程需发送一系列命令序列,包括设置像素格式、扫描方向、帧率控制等。扫描方向(MADCTL)可调整显示旋转角度,需根据实际硬件布局配置。

a967gsvj的博客 373

MFC控制条窗口布局原理(上)

 MFC控制条窗口布局原理——by Koote Bi@fudan cse一、框架窗口让我们先从框架窗口开始。当框架窗口改变大小时会收到WM_SIZE消息,CFrameWnd::OnSize负责处理此消息,该函数调用RecalcLayout来重新安置各子窗口,它的主体代码如下:if(GetStyle() & FWS_SNAPTOBARS){CRect rect(0, 0, 32767, 32767)

herb2008的专栏 939

设计空间探索:乘法器设计的面积、延时、功耗优化

4-2压缩器在减少延迟方面表现出色,适用于需要快速压缩的场景。6-2压缩器在资源占用方面具有优势,能够减少压缩树的层次数量和逻辑门数量。优化功耗:通过合理组合不同类型的压缩器,可以在延迟、资源占用和功耗之间找到最佳平衡点,从而实现优化的设计目标。###参考资料。

SiArch的博客 1879

macOS Jdk1.8安装(目前主流版本的jdk)

添加环境环境变量,类似于windows的高级设置中path配置的环境变量。查看 JAVA_HOME 目录。查看 JDK 版本信息。一直下一步安装就好了。在终端的根目录下运行。

m0_50207524的博客 9352

MFC控制条窗口布局原理【转】

一、框架窗口 框架窗口在其大小被改变的时候会收到WM_SIZE消息,这个消息的处理函数是CFrameWnd::OnSize,此函数接着调用RecalcLayout来重新安置各子窗口,它的主体代码如下: if(GetStyle() & FWS_SNAPTOBARS) { CRect rect(0, 0, 32767, 32767); RepositionBars(0, 0xffff, AF...

dazhilao 222

避坑指南:为什么你的conda环境装不上Mamba?从CUDA到ABI的深度排查

本文深入解析conda环境中安装Mamba架构时常见的CUDA版本冲突、ABI不匹配等问题,提供从基础检查到深度排查的系统化解决方案。针对`causal-conv1d`和`mamba-ssm`安装失败场景,详细讲解PyTorch版本绑定、编译器工具链兼容性等关键技术要点,并给出预编译wheel选择、动态链接库配置等实用修复方案。

weixin_33738555的博客 345

理解MFC控制条窗口布局原理之一

 一、框架窗口  框架窗口在其大小被改变的时候会收到WM_SIZE消息,这个消息的处理函数是CFrameWnd::OnSize,此函数接着调用RecalcLayout来重新安置各子窗口,它的主体代码如下: if(GetStyle() & FWS_SNAPTOBARS){ CRect rect(0, 0, 32767, 32767); R

754

从实验室到生产线:Qwen3-Omni后训练技术在实际业务中的落地挑战

本文探讨了Qwen3-Omni后训练技术在实际业务中的落地挑战,重点分析了多模态AI在工业应用中的关键问题与解决方案。通过金融风控、跨境电商等场景案例,揭示了通用模型与垂直需求的矛盾,并提供了知识蒸馏、语音合成优化等实战经验,助力企业实现技术到业务的转化。

weixin_29035147的博客 266

✨在Windows11上安装虚拟机(VMware17.6.0)保姆级教程(附安装包)

VMware Workstation Pro 是一款功能强大的虚拟机软件,它允许你在单一的物理机上运行多个操作系统。性能卓越:VMware以其出色的性能和稳定性而闻名,适合运行资源密集型的虚拟机。用户友好:直观的用户界面使得即使是初学者也能快速上手。功能全面:支持多种操作系统,包括Windows、Linux、macOS等,满足不同用户的需求。企业级支持:VMware提供全面的技术支持,适合企业级用户。恭喜你成功安装了VMware Workstation Pro 17.6.0!

Python老吕的博客 1万+

MFC教程-13

 MFC工具条和状态栏 Windows控制窗口 Windows (Windows95或者以上版本) 提供了系列通用控制窗口,其中包括工具条(ToolBar)、状态栏(StatusBar)、工具条提示窗口(ToolTip)。Windows在一个DLL加载时注册个控制窗口的“窗口类”。例如,工具条的“窗口类”是 “ToolbarWindow32”,状态栏的“窗口类”是“ms

JidanIt的专栏 1523

五、MT8168 音频驱动之SPEAKER

本章主要讲解MT8168平台的内部SPEAKER驱动配置。分为HP接法和LINE OUT接法。2.1.3 audio_custom_exp.h设置。2.1.4 mixer_paths.xml设置。2.2.3 mixer_paths.xml设置。2.1.2 ProjectConfig 设置。2.2.2 ProjectConfig 设置。2.2.1 deconfig设置。2.1.1 DTS设置。......

Joon2020的博客 1664

理解MFC控制条窗体布局原理 转

理解MFC控制条窗口布局原理之一2007-08-30 08:53作者:Koote Bi@fudan cse出处:论坛整理责任编辑:方舟一、框架窗口<br /><br />  框架窗口在其大小被改变的时候会收到WM_SIZE消息,这个消息的处理函数是CFrameWnd::OnSize,此函数接着调用RecalcLayout来重新安置各子窗口,它的主体代码如下:<br /><br />if(GetStyle() & FWS_SNAPTOBARS)<br />{<br /> CRect rect(0, 0, 32

feihuadao的专栏 1981

T527 uart串口配置导致系统进不去

T527 s_uart串口配置导致系统进不去。

Linux驱动开发工程师,熟悉Linux/Android底层驱动、TP、显示、IIC、网络等通用外设调试适配,Linux上层应用开发。常用平台瑞芯微、全志、恩智浦等。 675

WINCC7.3破解文件

WINCC7.3硬件够破解文件,有需要的下载!WINCC7.3硬件够破解文件,有需要的下载!

如何用MFC在窗口中绘制曲线

如何用MFC在窗口中绘制曲线? [问题点数:20分,结帖人u010266343]             不显示删除回复           显示所有回复            显示星级回复           显示得分回复            只显示楼主          收藏 关注 u010266343 河水0 本版等级:

autumn20080101的专栏 3409

C# WinForm 基于DirectShow.dll编写的程序,可边预览边保存视频,音频和图片

基于微软的DirectShow.dll的二次开发1.自动识别连接的摄像头跟麦克风且可以对其进行选择(默认选中第一个)2.可录制wmv和avi两种格式的视频并且都带有音频,avi可以录制的分辨率和帧数进行选择,wmv默认进行了淸晰度优化如不喜欢可去除代码中有相关提示3.可在预览点开之后进行拍照,也可边录制视频边拍照4.添加了视频和音频的压缩功能(酌情使用)这次二次开发发现C#对DirectShow的相关信息太少,这次做完也不敢藏私共享出来,还望大家指正

上一篇: MFC窗口位置管理详细分析及实例
下一篇: The Debug Library in Lua 选择自 xbcqu 的 Blog
skyremember
博客等级 码龄20年 204粉丝 484原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值