InvalidateRect()与Invalidate()

  

void Invalidate( BOOL bErase = TRUE );
该函数的作用是使整个窗口客户区无效。窗口的客户区无效意味着需要重绘,例如,如果一个被其它窗口遮住的窗口变成了前台窗口,那么原来被遮住的部分就是无效的,需要重绘。这时Windows会在应用程序的消息队列中放置WM_PAINT消息。MFC为窗口类提供了WM_PAINT的消息处理函数OnPaint,OnPaint负责重绘窗口。视图类有一些例外,在视图类的OnPaint函数中调用了OnDraw函数,实际的重绘工作由OnDraw来完成。参数bErase为TRUE时,重绘区域内的背景将被擦除,否则,背景将保持不变。

它和 UpdateWindow( )区别在于:
UpdateWindow( )的作用是使窗口立即重绘。调用Invalidate等函数后窗口不会立即重绘,这是由于WM_PAINT消息的优先级很低,它需要等消息队列中的其它消息发送完后才能被处理。调用UpdateWindow函数可使WM_PAINT被直接发送到目标窗口,从而导致窗口立即重绘。

当需要更新窗口的时候可以使用Invalidate()来重绘整个窗口,但是重绘整个窗口计算量是很大的,这会导致屏幕出现闪烁,为了防止这种情况,可以用InvalidateRect()来替代Invalidate(),毕竟计算一个矩形里面要绘制的内容计算量会要小很多。
函数原型:
BOOL InvalidateRect(
HWND hWnd, //需要重绘的窗口的句柄
LPCRECT lpRect, //要重绘的矩形区域
BOOL bErase = TRUE //重绘矩形的方式。
);
InvalidateRect()的第一个参数是需要重绘的窗口的句柄,但是似乎在CView类及它的派生类中可以不要填写,第二个参数是一个CRect矩形类,矩形的坐标必须是逻辑坐标。第三个参数是重绘矩形的方式,为FALSE是重绘传入的矩形,为TRUE的时候似乎是重绘整个窗口。

关于逻辑坐标(LP - Logical Point)和设备坐标(DP – Device Point)
对于屏幕,逻辑坐标的原点在最左下角,让整个屏幕在坐标轴的第一象限。设备坐标是在输出设备上定点绘制图形对象是用的,它采用笛卡尔坐标系,原点在屏幕的最左上角,x轴的值自左向右增加,y轴自右向左增加,单位为像素(设备单位)。另外设备坐标是绝对的,逻辑坐标是相对的,可以根据窗口的位置变化来变化的,引用逻辑坐标,就是为了更加直观的来表示屏幕的坐标。还有一种物理坐标,实际上就是设备坐标。

关于逻辑坐标和设备坐标的转换
逻辑坐标转换成设备坐标的函数:
函数原型:
BOOL LptoDP(
LPPOINT lpPoints, 指向POINT结构数组的指针,每一个POINT结构中的X坐标和Y坐标将被转换
int nCount, //指定数组中点的数目,不写则为1
HDC hdc //指向设备环境的句柄。我在写程序的时候,似乎没有写哦,不过也通过了,会不会又是因为写在了CView类里面的原因呢?
);
如果函数调用成功,返回值为非零值。否则为零。
使用:
CPoint pt(0, 0);
pDC->LPtoDP(&pt);

逻辑坐标转换成设备坐标的函数:
函数原型:
BOOL DptoLP(
HDC hdc, //指向设备环境的句柄。还是没有写过……-_-!!!...
LPPOINT lpPoints, //指向POINT结构数组的指针,每个POINT结构中的X和Y坐标将被转换
int nCount, //规定数组中点的数目,不写则为1
);
如果函数调用成功,返回值为非零值。否则为零。
使用:
CPoint pt(0, 0);
pDC->DPtoLP(&pt);
注意,里面接的参数不是矩形,而是CPoint类。

———————————————————————————————————————————————

当客户区需要重绘时,调用CWnd的Invalidate或InvalidateRect成员函数来触发Windows的WM_PAINT消息,从而引起对OnDraw函数的调用。下面将详述 InvalidateRect。

InvalidateRect和WM_PAINT
InvalidateRect(&rect,TRUE)将调用Windows API的InvalidateRect(m_hWnd, lpRect, bErase),会向Windows添加一个无效区域,并发送一个WM_PAINT消息要求系统重绘这个无效区域rect,在OnPaint中,系统响应WM_PAINT消息,OnPaint将调用CPaintDC dc(this)以得到绘图设备上下文,CPaintDC::CPaintDC(CWnd* pWnd)是CPaint的构造函数,从其中可以看到系统将调用CDC* ::BeginPaint(m_hWnd = pWnd->m_hWnd, &m_ps),其中m_ps是一个LPPAINTSTRUCT结构,它包含有一个rcPaint成员,它代表当前的剪取区域,也就是当前的无效区域,这里它等于InvalidateRect(&rect,TRUE)传入的rect矩形区域,此时我们便可以且只能在这个矩形区域内绘图,也就是说如果我们此时绘制的图形超过了这个矩形区域,程序将自动截断超出部分,只在该区域内绘图,可以在InvalidateRect后,或在OnPaint中使用CRect brect;GetUpdateRect(&brect)得到这个裁剪区域。也可以通过在OnPaint中得到dc后使用CRect mrect=dc.m_ps.rcPaint得到这个裁剪区域。如果没有显式的声明CPaintDC dc(this),系统将自己生成一个绘图设备上下文,此时也可以使用GetUpdateRect得到裁剪区域,但此时系统没有将我们需要的rect传递给rcPaint,所以此时得到的区域将是整个客户区,所以当在OnPaint中没有CPaintDC dc(this)时,程序将强制重画整个客户区,当有了CPaintDC dc(this)时,由于显式调用了带参数的构造函数,rect将传递给dc,此时强制绘图的区域将是rect。至于InvalidateRect(&rect,TRUE)的第二个参数代表是否用背景重画,就是是否用背景颜色画刷填充剪取的无效区域rect,true代表用背景重画,flase代表不用背景重画。所以只要在OnPaint中显式地构造了一个CPaintDC设备上下文,程序就将得知当前的裁剪区域是rect,而如没有显示构造,系统将按默认的绘图方式绘制,此时裁剪区域是整个区域


你可能感兴趣的:(InvalidateRect()与Invalidate())