当前位置:C++技术网 > 精选软件 > 判断窗口有没有无效矩形即判断窗口是否需要刷新以及无效矩形有多大

判断窗口有没有无效矩形即判断窗口是否需要刷新以及无效矩形有多大

更新时间:2015-12-14 13:44:12浏览次数:1+次

    我们经常听说无效矩形,也听说过客户区重绘这些概念。然而你知道如何判断窗口是否存在无效矩形或者说窗口客户区是否需要重绘吗?如果无效矩形存在,有多大吗?
    这些信息对我们程序来讲,有些地方很有用。暂时一下子我也列举不出来,这个在局部刷新的地方,想提高重绘效率的地方肯定用得到。不管怎么样,我们先来学习一下。要想深入学习Win32这个知识点的学习是必不可少的。
    我们要查询和判断无效矩形区域的函数为GetUpdateRect。为什么这个函数叫做GetUpdateRect而不是叫做GetInvalidateRect呢?实际上,UpdateRect指的是要更新的区域,InvalidateRect指的是无效区域。实际上差不多,只是说法不一样。
    在处理客户区重绘的时候,会先让无效区域变为有效,然后在这个无效区域范围内绘制。那么这个无效区域就是要更新的区域。无效区域是比较靠前的说法,更新区域则是靠后的说法,依据逻辑的发展顺序,无效区变为有效区就可以开始绘制,也就成了更新区域。这一段话,纯粹是我说出来帮你理解这个函数的名称,让你深刻记住这个函数的作用,也解释这个函数名的疑问。
    对于函数的使用最官方的就是MSDN了。所以我也是要查询MSDN的,你在不知道一个函数使用时第一反应要是MSDN哦。
    在MSDN中,GetUpdateRect函数的声明如下:
BOOL GetUpdateRect(HWND hWnd,LPRECT lpRect,BOOL bErase);

    第一个参数时窗口的句柄,指示是要获取哪个窗口的无效矩形信息。第二个参数是接收得到的无效矩形的信息的RECT结构体指针。如果有多个无效区域,那么这个结构体就存储了包含多个无效矩形的最小矩形。如果这个参数设置为NULL,那么函数返回值为非零,表示存在无效矩形,否则返回0表示不存在无效矩形。这个特点就可以用来判断无效矩形是否存在。这个就是判断是否是因为无效矩形导致的WM_PAINT消息。因为只要存在无效矩形,就会产生WM_PAINT消息。

     这个窗口同时有两个小的分开的无效矩形(示意图)

这个窗口同时有两个小的分开的无效矩形(示意图)

        合并之后的包含两个小无效矩形的最小无效矩形即最外面的矩形

合并之后的包含两个小无效矩形的最小无效矩形即最外面的矩形

    在《WM_PAINT消息处理中的客户区重绘消息死循环问题详细分析和代码验证》一文中,我详细解释了WM_PAINT和无效矩形的关系,无效矩形存在一定要产生WM_PAINT消息。然而WM_PAINT的产生并不会全部因为无效矩形,因为你可以使用SendMessage或者PostMessage函数发送这个消息。此时并不存在无效矩形,因此没有必要对无效矩形进行重绘。通过这个函数的判断,就可以进行重绘的优化。
    第二个参数的传递使用如下:
RECT rect;
GetUpdateRect(hWnd,&rect,FALSE);
    第三个参数是否要擦除无效矩形区域的背景,如果为TRUE,且确实存在无效矩形,那么就会发送一个WM_ERASEBKGND擦除背景的消息去处理擦除背景。如果为FALSE表示不擦除无效区域的背景。这里指的不是整个客户区的背景,只是无效区域底下的背景。
    那么,了解了这个函数后,我们就知道了,可以通过设置第二个参数为NULL实现判断是否存在无效矩形。而传入一个RECT结构体变量地址就可以得到无效矩形的大小。
    原理都懂了,下面是效果图:
    判断无效矩形存在,且获取到了无效矩形大小
下面直接看代码:
#include "windows.h"
#include <tchar.h>
// - 项目是Unicode字符集
LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    RECT rect,rect1;
    int i;
    TCHAR Msg[100]=_T("");
    switch (message)
    {
     case WM_PAINT:
         hdc = BeginPaint(hwnd,&ps);//会清除无效矩形
         EndPaint(hwnd,&ps);
        return 0;
     case WM_LBUTTONDOWN:
         rect.left=0;
         rect.top=0;
         rect.right=100;
         rect.bottom=100;
         InvalidateRect(hwnd,&rect,FALSE);// - 设置无效矩形的大小
         if(GetUpdateRect(hwnd,NULL,FALSE))// - 判断无效矩形是否存在
         {
             GetUpdateRect(hwnd,&rect1,TRUE);//-获取无效矩形的大小
             wsprintf(Msg,_T("无效矩形区域:x=%d,y=%d,宽=%d,高=%d"),rect1.left,rect1.top,rect1.right,rect1.bottom);
             MessageBox(hwnd,Msg,_T("C++技术网提示"),MB_OK);
         }
         else
         {
             MessageBox(hwnd,_T("没有无效区域"),_T("提示"),MB_OK);
         }
         return 0;
     case WM_DESTROY:
         PostQuitMessage(0);
         return 0;
     default:
         return DefWindowProc(hwnd, message, wParam, lParam);
    }
}
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrev,LPSTR lpCmd,int iShow)
{
    TCHAR ClassName[] = _T("MyClass");
    TCHAR title1[] = _T("C++技术网http://www.cjjjs.com");
    WNDCLASS wndClass;
    wndClass.cbClsExtra=0;
    wndClass.cbWndExtra=0;
    wndClass.hbrBackground= (HBRUSH)GetStockObject(GRAY_BRUSH);
    wndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
    wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
    wndClass.hInstance = hInstance;
    wndClass.lpfnWndProc = WinProc;
    wndClass.lpszClassName = ClassName;
    wndClass.lpszMenuName=NULL;
    wndClass.style=CS_HREDRAW|CS_VREDRAW;

    if(!RegisterClass(&wndClass))
    {
        return 0;
    }

    HWND hwnd = CreateWindow(ClassName,title1,WS_OVERLAPPEDWINDOW,0,0,440,400,NULL,NULL,hInstance,NULL);
    ShowWindow(hwnd,SW_SHOWNORMAL);

    MSG msg;
    while (GetMessage(&msg,NULL,0,0))
    {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}