介绍

  窗口的大小和位置表示为一个矩形边界,该矩形的坐标是相对于屏幕或父窗口而言的。顶级窗口的坐标是相对于屏幕的左上角而言的,子窗口的坐标则是相对于父窗口的左上角而言。应用程序创建窗口时(CreateWindowEx())指定一个窗口的初始大小和位置,但也可以在任何时候改变窗口的大小和位置。

关于初始的位置和大小

使用VS生成一个Win32程序时,可以看到VS已经帮助我们做了很多工作(虽然有些是多余的)。他帮助咱么创建的窗口就使用了默认大小

 HWND hWnd = CreateWindowW(szWindowClass,                    //窗口类名称,字符串指针
szTitle, //窗口名称,显示在标题栏,字符串指针
WS_OVERLAPPEDWINDOW, //窗口风格,顶层窗口一般都是该风格
CW_USEDEFAULT, //窗口位置的x值
, //窗口位置的y值
CW_USEDEFAULT, //窗口的横向尺寸
, //窗口的纵向尺寸
nullptr, //父窗口句柄,顶层窗口没有父窗口
nullptr, //子窗口ID或菜单句柄,HMENU类型
hInstance, //实例句柄
nullptr); //额外参数的指针

这里只关心与位置和尺寸有关的参数(第4-7个参数)。效果看图(主要看窗口位置和大小)。可是为什么呢,窗口位置的y值和窗口的纵向尺寸不是0吗?

这和CW_USEDEFAULT宏有关,当窗口的横坐标是该值时CreateWindowEx就忽略纵坐标而选择一个合适的位置产生窗口(所谓合适是Windows觉得合适,你不一定这么想)。注意该宏仅对WS_OVERLAPPEDWINDOW风格的窗口有效,对WM_CHILD或WM_POPUP不管用。提供一个自以为是的默认设置,这是微软的一贯方法,这难道不是暴君的风格吗?因为很多时候这个默认位置并不是咱们想要的。好在微软没有过分独裁,他给了程序员决定窗口位置的自由。自由的代价一直昂贵,我们必须为此多些几行代码来换取这个奢侈的自由。

不要想着在CreateWindowEx()中直接指定数值,这样的代码并不健壮,天晓得你的程序会在什么电脑上运行,也许他的屏幕都没有你想创建的窗口大。所以先获取屏幕的大小,再决定自己客户区的大小,最后推算整个窗口的尺寸和位置。比如在屏幕正中创建一个客户区大小为屏幕1/4的含菜单栏的顶层窗口:

  int cxScreen = GetSystemMetrics(SM_CXSCREEN);
int cyScreen = GetSystemMetrics(SM_CYSCREEN);
RECT rect = {};
rect.left = cxScreen / ;
rect.right = cxScreen * / ;
rect.top = cyScreen / ;
rect.bottom = cyScreen * / ;
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, TRUE);
HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
rect.left, rect.top,rect.right-rect.left, rect.bottom-rect.top, nullptr, nullptr, hInstance, nullptr);

响应用户对窗口调整的需求

一般的窗口应该可以响应鼠标的拉伸来改变自己的大小。特殊的时候也可以选择只有固定大小,或者大小可以改变但保持纵横比例不变。WS_OVERLAPPED风格的窗口的大小是不能通过拖拽边框改变的(这不是说他没有边框,即使包含WS_BORDER也不行,实际上,顶层窗口总有边框,WM_BORDER一般是和WS_CHILD一起用的)。包含WS_THICKFRAME风格(或WS_SIZEBOX,二者完全一样)则可以通过拖拽边框改变(如果再包含WS_SYSMENU,右击标题栏则可以看到“大小(S)”是可用的,否则即使包含WS_SYSMENU“大小(S)”也是灰色的。同样只有含有WS_MINIMIZEBOX/最小化才是可用的,如图)。

PS:WS_MINIMIZEBOX和WS_MINIMIZE是不一样的,后者意味着窗口初始即为最小化的。

也许你允许用户改变尺寸但想限制尺寸在一定范围内,做法是使用WS_SIZEBOX并且处理 WM_GETMINMAXINFO  消息,窗口位置或尺寸将要改变时会受到该消息。这个消息的wparam是一个结构指针,这个结构包含了窗口的默认最大尺寸和默认最小尺寸:

typedef struct tagMINMAXINFO {
POINT ptReserved;       //保留
POINT ptMaxSize;       //最大尺寸
POINT ptMaxPosition;     //最左上角的位置
POINT ptMinTrackSize;    //最小伸缩尺寸
POINT ptMaxTrackSize;    //最大伸缩尺寸
} MINMAXINFO, *PMINMAXINFO, *LPMINMAXINFO;  //对顶层窗口所有坐标针对屏幕,如果有多个屏幕,相对主显示器。

当含有系统菜单时,也可以通过系统菜单的命令来改变大小或位置,窗口会收到WM_SYSCLOSE,WM_SYSSIZE等消息,你可以处理它们,也可以交给DefWindowPro。

调整窗口位置大小的函数

SetWindowPlacement 设置窗口的最小化最大化位置,还原时的大小和位置,显示状态。 MoveWindow and SetWindowPos 功能一样 都可以设置单个窗口的大小和位置。但是 SetWindowPos还可以通过一系列标志影响窗口的显示状态,MoveWindow则不可以。 BeginDeferWindowPosDeferWindowPos, 和 EndDeferWindowPos 可以设置多个窗口的位置大小,Z-order和显示状态。

GetWindowRect  获得窗口的大小

ScreenToClient   把屏幕坐标转换成客户区坐标

MapWindowPoints 把一系列点的坐标从相对一个窗口转化到相对另一个窗口(坐标系变换)

GetClientRect    获得客户区大小

CascadeWindowsTileWindows 以层叠方式排列窗口或以铺展方式排列窗口。

调整窗口位置或大小时收到的消息

WM_GETMINMAXINFO  位置或大小将要改变时,前面说过该消息。注意调用SetWindowPos时也会收到该消息。

WM_WINDOWPOSCHANGING   大小位置,Z-order,显示状态将要改变时

WM_WINDOWPOSCHANGED    大小位置,Z-order,显示状态改变之后,主要是要保证把该消息给DefWindowPro

两个消息的lparam都是指向WINDOWPOS结构的指针,咱们来测试一下:

结果是在WM_WINDOWPOSCHANGING中设置WINDOWPOS的各项为固定值将锁定窗口的位置和大小。

而在WM_WINDOWPOSCHANGED中设置WINDOWPOS不会影响窗口位置大小的改变。实际上该消息通过WINDOWPOS来返回移动后的值。

PS:只有顶层窗口和POPUP窗口才会有上面两个消息。

WM_SIZE 和 WM_MOVE     DefWindowPro处理WM_WINDOWPOSCHANGED时会send(不是POST)这两个消息,拦截WM_WINDOWPOSCHANGED就无法收到这两个消息。这两个消息告诉程序窗口是否被最大化或最小化。建议在自己的窗口过程中忽略WM_WINDOWPOSCHANGED消息,而处理WM_SIZE和WM_MOVE消息。

WM_NCCALCSIZE    窗口大小位置改变时发送该消息,DefWindowPro收到该消息后计算客户区的大小位置,一般把该消息交给DefWindowPro。拦截该消息将导致系统不能自动绘制非客户区,可以处理该消息以达到定制非客户区样式的目的,这听上去很有趣,我将另写一篇文章来尝试这个效果(自定义的窗口样式)。

Windows窗口的尺寸和位置的更多相关文章

  1. Windows 系统上用 .NET/C# 查找所有窗口,并获得窗口的标题、位置、尺寸、最小化、可见性等各种状态

    原文:Windows 系统上用 .NET/C# 查找所有窗口,并获得窗口的标题.位置.尺寸.最小化.可见性等各种状态 在 Windows 应用开发中,如果需要操作其他的窗口,那么可以使用 EnumWi ...

  2. Windows窗口消息大全(转)

    Windows窗口消息大全,全不全自己看 ////////////////////////////////////////////////////////////////////////// #inc ...

  3. Windows窗口消息大全

    ////////////////////////////////////////////////////////////////////////// #include "AFXPRIV.H& ...

  4. C语言Windows程序开发—Windows窗口样式与常用控件样式【第04天】

    (一)Windows窗口(MDICLIENT)样式介绍 /* Windows窗口样式 */ WS_BORDER //带有边框的窗口 WS_CAPTION //带有标题栏的窗口 WS_CHILD //子 ...

  5. web前端开发中常用的尺寸和位置

    我们在日常web前端开发过程中,会经常用到各种尺寸和位置.通常是js做动画的时候.轮播图,滚屏动画,粒子,碰撞检测,拖拽,滚动加载等等.这里我将常用的尺寸和位置的获取进行总结,不包括canvas,SV ...

  6. 【转】Windows 窗口层次关系

    原文链接:undefined! 相信在Windows 下面编程的很多兄弟们都不是很清楚Windows 中窗口的层次关系是怎么样的,这个东西很久已经研究过一下,后来又忘记了,今天又一次遇到了这个问题,所 ...

  7. 在WPF控件上添加Windows窗口式调整大小行为

    起因 项目上需要对Canvas中的控件添加调整大小功能,即能在控件的四个角和四条边上可进行相应的拖动,类似Windows窗口那种.于是在参考以前同事写的代码基础上,完成了该功能. 代码实现 Adorn ...

  8. 按键精灵 句柄 获得句柄 控制windows窗口 后台

    新建一个文本文档,打开,Windows就会给这个文本文档的窗口临时分配唯一的一串数字来标识这个窗体,以区别于其他窗口,这串数字就叫句柄.   因为句柄是临时随机分配的,所以每次虽然是打开同一个文件,但 ...

  9. windows窗口分析,父窗口,子窗口,所有者窗口

    (本文尝试通过一些简单的实验,来分析Windows的窗口机制,并对微软的设计理由进行一定的猜测,需要读者具备C++.Windows编程及MFC经验,还得有一定动手能力.文中可能出现一些术语不统一的现象 ...

随机推荐

  1. IOC容器的依赖注入

    1.依赖注入发生的时间 当Spring IoC容器完成了Bean定义资源的定位.载入和解析注册以后,IoC容器中已经管理类Bean定义的相关数据,但是此时IoC容器还没有对所管理的Bean进行依赖注入 ...

  2. 【响应式】foundation栅格布局的“尝鲜”与“填坑”

      提到响应式,就不得不提两个响应式框架--bootstrap和foundation.在标题上我已经说明白啦,今天给大家介绍的是foundation框架. 何为"尝鲜"?就是带大伙 ...

  3. 系统启动 之 Linux系统启动概述(2)

    博客:http://blog.csdn.net/younger_china/article/details/51615916 Linu系统启动是一个"冗长乏味"的过程,那么我们现就 ...

  4. shell 分割字符串存至数组

    shell 分割字符串存至数组 shell编程中,经常需要将由特定分割符分割的字符串分割成数组,多数情况下我们首先会想到使用awk但是实际上用shell自带的分割数组功能会更方便.假如a=”one,t ...

  5. Laravel 5.2 教程 - 文件上传

    一.简介 Laravel 有很棒的文件系统抽象层,是基于 Frank de Jonge 的 Flysystem 扩展包. Laravel 集成的 Flysystem 提供了简单的接口,可以操作本地端空 ...

  6. MYSQL设置远程账户登陆总结

    为了给MYSQL用户设置远程连接权限,经历的种种错误总结 ERROR 2003 (HY00 原因是MySQL考虑到安全因素,默认配置只让从本地登录 打开 /etc/mysql/my.cnf 文件,找到 ...

  7. 产品经理学Python:条件控制

    条件控制其实就是if...else...(如果...条件是成立的,就做...:反之,就做...)的使用,其基本结构是: 具体看下面这个例子: def account_login(): # 定义函数 p ...

  8. 时间序列预测之--ARIMA模型

    什么是 ARIMA模型 ARIMA模型的全称叫做自回归移动平均模型,全称是(ARIMA, Autoregressive Integrated Moving Average Model).也记作ARIM ...

  9. hdu3336 Count the string kmp+dp

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3336 很容易想到用kmp 这里是next数组的应用 定义dp[i]表示以s[i]结尾的前缀的总数 那么 ...

  10. [刷题]算法竞赛入门经典(第2版) 5-4/UVa10763 - Foreign Exchange

    题意:有若干交换生.若干学校,有人希望从A校到B校,有的想从B到C.C到A等等等等.如果有人想从A到B也刚好有人想从B到A,那么可以交换(不允许一对多.多对一).看作后如果有人找不到人交换,那么整个交 ...