1.重绘抛出的问题
WM_PAINT事件发生的时候,windows会将当前窗口的状态设置为invalid无效状态。使用BeginPaint()-EndPaint()后,会将窗口恢复到valid有效状态。
(个人理解:WM_PAINT就是当窗口为invalid的状态是触发的消息)
在响应WM_PAINT事件后,对屏幕进行重绘,使用:
1 | PAINTSTRUCT ps; |
BeginPaint()和EndPaint()中的HWND参数表示要绘画的窗口。
BeginPaint(hWnd,&ps)中,会将屏幕需要重绘的部分返回到ps.rcPaint中(也就是说,只重绘需要的部分)
但同时,也抛出一个问题,就是我们只能访问需要重绘的部分,其他部分获取不到。
2.获取对整个窗口的访问权
HDC表示设备描述,在学习过《3D游戏编程大师技巧》之后,作者也是将一堆需要配置的东西写成了一个struct,避免每次添加或者修改配置字段都要改许多地方。
同理,HDC就是所有的设置。相关函数根据HDC中的设置进行不同的调用。
HDC中含有队整个窗口的图形设备的设置。
获取HDC的方法是:
1 | hdc=GetDC(hwnd); // 获取某个窗口hwnd的hdc |
在处理完成hdc之后,需要归还,调用方法原型是:
1 | int ReleaseDC(HWND hwnd, // 哪个窗口 |
这个时候绘制全屏的过程是:
1 | HDC hdc=NULL; |
出现的新问题是,使用GetDc()-ReleaseDC()并不会触发使窗口valide的设置。只要窗口没有被设置为valid,那么这个WM_PAINT消息将会一直传递下去。
3.绘制整个窗口方法一
GetClientRect()函数用于获取用户矩形区域的坐标。
(窗口坐标是相对于显示器屏幕的坐标,用户坐标是相对于窗口坐上角(0,0)点的)
ValidateRect()函数改变窗口状态为valide有效状态:
函数原型:1
2BOOL ValidateRect(HWND hWnd, // 窗口
CONST RECT *lpRECT); // 设置为有效状态的rect区域
因此,正确的绘制整个窗口的流程为:
1 | PAINTSTRUCT ps; |
4.绘制整个窗口方法二
先使得整个窗口矩形都变为无效,然后再调用BeginPaint()-EndPaint()
使窗口矩形变为无效的函数原型是:1
2
3BOOL InvalidateRect(HWND hWnd, // 窗口
CONST RECT *lpRect, // 矩形区域
BOOL bErase); // 是否擦除背景
当lpRect参数为NULL的时候,将使整个窗口的矩形区域变为无效。
流程代码为:
1 | PAINTSTRUCT ps; |
5.总结
- 窗口有invalid的部分时,会触发WM_PAINT事件
- BeginPaint()-EndPaint()只会重绘无效区域,并且将无效区域状态设置为valide
- GetDC()-ReleaseDC()获取和释放hdc
- ValidateRect()函数将rect区域设置为有效valid
- InvalidateRect()函数将rect区域设置为无效invalid
- GetClientRect()函数获取窗口的整个区域
以上。