WM_NCCALCSIZE消息处理详解
【前言】
指定应用程序的标题高度和边框的宽度的方法有很多种。其中最普遍的方法有下面的两种:
第一种:创建没有标题栏应用程序,在客户区让出一部分空间用一幅图片画一个标题栏,让人“误认为”是标题栏。
第二种:处理应用程序接收到的WM_NCCALCSIZE消息,改变客户区在窗口中的位置,从而得到合适标题栏高度。
不能说哪一种方法好,哪一种方法不好,其实第一种做法简单易行,而且也能做得很漂亮,但不爽的一点是就是每一次画客户区的时候总是计算坐标的起始位置;第二种方法有点麻烦(其实也不麻烦),但有一点很好,客户区不用负责标题栏重绘工作,响应WM_PAINT消息时候不用计算位置。
【第二种】
要想得到最准确最全面的信息得去MS的老巢去找EN文版的(GOOGLE什么的最讨厌了),别怕一句一句看(俺的英语水平(360) << CET-4(425),我都能看懂,肯定没有人看不懂的了)。
wParam:
If wParam is TRUE, it specifies that the application should indicate which part of the client area contains valid information. The system copies the valid information to the specified area within the new client area.
If wParam is FALSE, the application does not need to indicate the valid part of the client area.
lParam:
If wParam is TRUE, lParam points to an NCCALCSIZE_PARAMS structure that contains information an application can use to calculate the new size and position of the client rectangle.
If wParam is FALSE, lParam points to a RECT structure. On entry, the structure contains the proposed window rectangle for the window. On exit, the structure should contain the screen coordinates of the corresponding window client area.
这是MSND上一段话:意思是如wParam为TRUE,需要在新矩形中指定可用的客户区;如果wParam为FALSE应用程序不用在新矩形中指定客户区。
我这样的理解的:当窗口创建时候的wParam为FALSE,其它情况为TRUE。
【TRUE情况】
假想:窗口一开始在A位置,突然移动到B位置。
如图:
这时候Windows将会给窗口发送一个WM_NCCALCSIZE消息,通知应用程序窗口的位置或者大小变了,应用程序应当指定新的非客户区和客户区的位置。消息具体内容的是:
message:WM_NCCALCSIZE
wParam: TRUE
lParam: 一个指向三个矩形的指针(NCCALCSIZE_PARAMS *)。下面是NCCALCSIZE_PARAMS结构:
typedef struct tagNCCALCSIZE_PARAMS {
RECT rgrc[3];
PWINDOWPOS lppos;
} NCCALCSIZE_PARAMS, *LPNCCALCSIZE_PARAMS;
下面是MSDN的一段说明:
rgrc
RECT
An array of rectangles. The meaning of the array of rectangles changes during the processing of the WM_NCCALCSIZE message.
When the window procedure receives the WM_NCCALCSIZE message, the first rectangle contains the new coordinates of a window that has been moved or resized, that is, it is the proposed new window coordinates. The second contains the coordinates of the window before it was moved or resized. The third contains the coordinates of the window's client area before the window was moved or resized. If the window is a child window, the coordinates are relative to the client area of the parent window. If the window is a top-level window, the coordinates are relative to the screen origin.
When the window procedure returns, the first rectangle contains the coordinates of the new client rectangle resulting from the move or resize. The second rectangle contains the valid destination rectangle, and the third rectangle contains the valid source rectangle. The last two rectangles are used
简易翻译一下(凑合看):
当窗口处理收到的WM_NCCALCSIZE消息是,第一个矩形包含了移动后或者改变大小后的新坐标(也就是B的坐标),它是建议的坐标。第二个矩形包含了移动或改变大小前的坐标(也就是A坐标),第三个矩形包含了客户区的移动前的坐标(也就是A坐标中的客户区坐标)。
处理这个消息返回之前(也就是WM_NCCALCSIZE处理完成后),第一个矩形应当包含新客户区的坐标(也就是B坐标中的客户区坐标),第二个矩形包含了可用的目标矩形(B坐标),第三个坐标包含了源矩形(A坐标)。后面的两个矩形也会被用到。简而言之:
我们在处理前的是:第一个矩形是B,第二个矩形是A,第三个矩形是AC,
我们在处理后的是:第一个矩形是BC,第二个矩形是B,第三个是矩形A。
于是我写下了下写的C处理代码:
int xFrame = 2; /*左右边框的厚度*/
int yFrame = 2; /*下边框的厚度*/
int nTHight = 40; /*标题栏的高度*/
NCCALCSIZE_PARAMS * p; /*TRUE是的指针*/
RECT * rc; /*FALSE是的指针*/
RECT aRect;
RECT bRect;
RECT bcRect;
if(wParam == TRUE)
{
p = (NCCALCSIZE_PARAMS *)lParam;
/*复制A B矩形位置*/
CopyRect(&aRect,&p->rgrc[1]);
CopyRect(&bRect,&p->rgrc[0]);
/*指定BC的矩形的位置*/
bcRect.left = bRect.left + xFrame;
bcRect.top = bRect.top + nTHight;
bcRect.right = bRect.right - xFrame;
bcRect.bottom = bRect.bottom - yFrame;
/*各个矩形归位成BC B A*/
CopyRect(&p->rgrc[0],&bcRect);
CopyRect(&p->rgrc[1],&bRect);
CopyRect(&p->rgrc[2],&aRect);
}
上面是处理了wParam为TRUE的情况,再回头来看FALSE的情况,就是初始化的时候,我们知道刚刚初始化的时候不是A->B而是从没有矩形到有矩形。
【FALSE情况】
这时候,lParam是指向一个矩形,这个矩形是窗口的现在位置X,我们要返回的是XC,也是就是返回X变成XC,下面给成C代码:
else
{
rc = (RECT *)lParam;
rc->left = rc->left + xFrame;
rc->top = rc->top + nTHight;
rc->right = rc->right - xFrame;
rc->bottom = rc->bottom - yFrame;
}
至此, WM_NCCALCSIZE讲解完毕。自定义高度的窗口式样(照着QQ风格画的):
nie@song.ah.cn
niesongsong
沈阳
敬上
整个函数写法:
case WM_NCCALCSIZE:
ProcNCCalcSize(hWnd,message,wParam,lParam);
int ProcNCCalcSize(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int xFrame = 2; /*左右边框的厚度*/
int yFrame = 2; /*下边框的厚度*/
int nTHight = 40; /*标题栏的高度*/
NCCALCSIZE_PARAMS * p;
RECT * rc;
RECT aRect;
RECT bRect;
RECT bcRect;
if(wParam == TRUE)
{
p = (NCCALCSIZE_PARAMS *)lParam; /*矩形是B A AC,目标是改成BC B A*/
CopyRect(&aRect,&p->rgrc[1]);
CopyRect(&bRect,&p->rgrc[0]);
/*指定BC的矩形的位置*/
bcRect.left = bRect.left + xFrame;
bcRect.top = bRect.top + nTHight;
bcRect.right = bRect.right - xFrame;
bcRect.bottom = bRect.bottom - yFrame;
/*各个矩形归位*/
CopyRect(&p->rgrc[0],&bcRect);
CopyRect(&p->rgrc[1],&bRect);
CopyRect(&p->rgrc[2],&aRect);
}
else
{
rc = (RECT *)lParam;
rc->left = rc->left + xFrame;
rc->top = rc->top + nTHight;
rc->right = rc->right - xFrame;
rc->bottom = rc->bottom - yFrame;
}
return GetLastError();
}
WM_NCCALCSIZE消息处理详解的更多相关文章
- Android多线程----异步消息处理机制之Handler详解
[声明] 欢迎转载,但请保留文章原始出处→_→ 生命壹号:http://www.cnblogs.com/smyhvae/ 文章来源:http://www.cnblogs.com/smyhvae/p/ ...
- linux查看端口及端口详解
今天现场查看了TCP端口的占用情况,如下图 红色部分是IP,现场那边问我是不是我的程序占用了tcp的链接,,我远程登陆现场查看了一下,这种类型的tcp链接占用了400多个,,后边查了一下资料,说E ...
- HTTP协议详解(转)
转自:http://blog.csdn.net/gueter/archive/2007/03/08/1524447.aspx Author :Jeffrey 引言 HTTP是一个属于应用层的面向对象的 ...
- HTTP协议详解
Author :Jeffrey 引言 HTTP 是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和 扩展. ...
- ASP.NET知识总结(3.HTTP协议详解)
引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1. ...
- 接口测试之HTTP协议详解
引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1. ...
- 【转】HTTP协议详解
原文地址:http://www.cnblogs.com/EricaMIN1987_IT/p/3837436.html 一.概念 协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则 ...
- HTTP协议详解(真的很经典)
HTTP 是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和 扩展.目前在WWW中使用的是HTTP/1.0 ...
- HTTP协议详解--转载http://blog.csdn.net/gueter/article/details/1524447
引言 HTTP是一个属于应用层的面向对象的协议,由于其简捷.快速的方式,适用于分布式超媒体信息系统.它于1990年提出,经过几年的使用与发展,得到不断地完善和扩展.目前在WWW中使用的是HTTP/1. ...
随机推荐
- POJ 3670 Eating Together (DP,LIS)
题意:给定 n 个数,让你修改最少的数,使得它变成一个不下降或者不上升序列. 析:这个就是一个LIS,但是当时并没有看出来...只要求出最长LIS的长度,用总数减去就是答案. 代码如下: #inclu ...
- git 入门学习笔记
安装msysgit (模拟环境Git)安装后绑定邮箱和名字$ git config --global user.name "Your Name"$ git config --glo ...
- ArcGIS Add-in开发(一)--获取选定要素的属性值
刚刚接触AE开发,记录一下自己的学习心得! 欢迎大家一起交流探讨! 最近做大赛,突然想到可以让项目更加直观的操作,就在项目中加了幅底图(底图很简单) 我想在arcmap中选中相应的要素后,在后台通过写 ...
- 很值得学习的java 画图板源码
很值得学习的java 画图板源码下载地址:http://download.csdn.net/source/2371150 package minidrawpad; import java.awt.*; ...
- 从零开始学android开发-通过WebService获取今日天气情况
因为本身是在搞.NET方面的东东,现在在学习Android,所以想实现Android通过WebService接口来获取数据,网上很多例子还有有问题的.参考:Android 通过WebService进行 ...
- CDOJ 1251 谕神的密码 贪心
谕神的密码 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/1251 Descr ...
- Codeforces Gym 100500F Problem F. Door Lock 二分
Problem F. Door LockTime Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/gym/100500/at ...
- IOS App动态更新
框架 JSPatch WaxPatch react-native 方案对比 目前已经有一些方案可以实现动态打补丁,例如WaxPatch,可以用Lua调用OC方法,相对于WaxPatch,JSPat ...
- Android XML文件布局各个属性详解
第一常用类:属性值为true或false android:layout_centerHrizontal 水平居中 android:layout_centerVertical 垂直居中 android: ...
- 超级强大的vim配置(vimplus)
vimplus vimplus是vim的超级配置安装程序 github地址:https://github.com/chxuan/vimplus.git,欢迎star和fork. 接触vim到现在也有几 ...