`

关于WM_ERASEBKGND和WM_PAINT的深刻理解

 
阅读更多

关于WM_ERASEBKGND和WM_PAINT的深刻理解

一直以来,对于WM_PAINT和WM_ERASEBKGND消息不是很清楚,从书上和网上找了很多资料,大体上有以下几点说法:

1.WM_PAINT先产生,WM_ERASEBKGND后产生

2.WM_PAINT产生后,在调用hdc = BeginPaint(hWnd, &ps); 如果ps.fErase为true,则BeginPaint会产生WM_ERASEBKGND消息

3.BeginPaint函数用来擦除窗口背景

4.WM_ERASEBKGND用来绘制背景

经过调试、分析,发现上面的说法并不正确。以下是一些测试代码,代码后面附上一些分析。最后总结出几点,可以解释程序中出现的所有关于窗口重绘的问题。

如有不正确的地方,大家可以指正。

为了说明问题,在此不说WM_NCPAINT消息(非客户区消息),只说WM_ERASEBKGND消息和客户区的WM_PAINT消息

先说一下程序运行时发现的一些现象:

1.上面的代码:如果添加了WM_ERASEBKGND消息,里面什么也不做,如下

case WM_ERASEBKGND:

break;

则当程序运行时,如果收到WM_ERASEBKGND消息,则这个switch-case结构中就不会执行默认消息处理函数DefWindowProc,运行时发现,窗口的背景就没有了,即背景为空。

这说明了窗口背景仅仅是由默认的消息处理函数DefWindowProc绘制的。

(注:注册窗口类时,背景设置为白色wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);)

2.如上面的代码,因为有WM_ERASEBKGND消息,则程序运行时窗口背景为NULL,但是如果添加了WM_LBUTTONDOWN消息,从里面调用默认窗口消息处理函数,如下:

case WM_LBUTTONDOWN:

{

HDC hdc;

hdc=::GetDC(hWnd);

WPARAM w=(WPARAM)hdc; //变量w作为WM_ERASEBKGND消息的wParam参数,保存了设备环境句柄

LPARAM l=0;

DefWindowProc(hWnd, WM_ERASEBKGND, w, l); //调用默认消息处理函数DefWindowProc

}

break;

程序运行时,如果用鼠标单击一下窗口客户区,则窗口的背景就会显示!这进一步说明了窗口的背景色是由默认消息处理函数DefWindowProc绘制的。

3.以上代码,因为添加了WM_ERASEBKGND消息,所以窗口背景是空。虽然在WM_PAINT消息中有hdc = BeginPaint(hWnd, &ps);函数的调用,但是窗口背景仍然是空,这说明了BeginPaint函数并不会擦除背景(即用默认画刷绘制窗口背景)。

BeginPaint函数只做了两件事情:

1)使窗口无效区域变得有效,从而使Windows不再发送WM_PAINT消息(直到窗口大小改变等,使窗口再次变得无效)。

(如果窗口一直无效,则Windows会不停地发送WM_PAINT消息)

2)填充PAINTSTRUCT结构。填充这个结构的目的,是让程序员可以根据ps变量中的标志值进行某些操作

4.调试的时候,发现:当窗口改变大小,或者其它操作使窗口变得无效时,WM_ERASEBKGND消息总是先于WM_PAINT消息发出,而且如果产生WM_ERASEBKGND消息,则最后一个WM_ERASEBKGND的下一条消息一定是WM_PAINT消息(WM_ERASEBKGND可能会连续产生几次)。WM_ERASEBKGND消息和WM_PAINT消息之间没有其它消息

-----------------------------------------------------------------------------------------------------------------------

以下是一些总结

1.窗口背景的擦除(即绘制)

窗口的背景色是由默认的消息处理函数DefWindowProc擦除的(即这个函数使用注册窗口类时使用的背景刷擦除窗口背景)。

什么时候绘制?在窗口函数收到WM_ERASEBKGND消息,DefWindowProc函数以WM_ERASEBKGND为参数,才会绘制窗口背景

(注:当WM_ERASEBKGND消息产生后,窗口一定有一部分变得无效)

2.窗口的无效:

当拖动窗口的一个顶点改变了窗口的大小、窗口由最小化恢复到最大化、窗口的一部分被其它窗口遮住又重新显示、调用MoveWindow函数改变了窗口大小、窗口移动到桌面之外的部分被拖回重新显示时,窗口就会变得无效。 无效区域是整个客户区,因此默认窗口处理函数DefWindowProc会擦除整个客户区。(注:拖动窗口标题栏移动窗口,只要窗口没有移动到屏幕之外,那么这两个消息都不产生)

当窗口无效时,Windows会给窗口发出WM_ERASEBKGND消息和WM_PAINT消息,而且WM_ERASEBKGND先发出一次或者几次,紧接着是WM_PAINT.例外:InvalidateRect函数的调用会使窗口变得无效,并产生WM_ERASEBKGND消息和WM_PAINT消息,而WM_ERASEBKGND是否产生取决于参数bErase

void InvalidateRect (

LPCRECT lpRect,

BOOL bErase = TRUE );

当参数bErase为true时,WM_ERASEBKGND消息产生,当bErase为false时WM_ERASEBKGND消息不产生

3.消息的处理过程。当窗口无效时,先发出WM_ERASEBKGND消息若干次-----------再发出WM_PAINT消息,WM_ERASEBKGND和WM_PAINT之间没有其它消息

WM_ERASEBKGND消息的后面一定是WM_PAINT

1)WM_ERASEBKGND消息的处理:

上面的代码,如果没有添加WM_ERASEBKGND,则默认的消息处理函数DefWindowProc会被调用,此时的DefWindowProc会擦除窗口背景(即绘制背景),并且ps.fErase会为FALSE。如果添加了WM_ERASEBKGND消息,DefWindowProc就不会被调用,则无法擦除窗口背景,并且ps.fErase会为true

2)WM_PAINT的处理

在这个消息中如果调用了hdc = BeginPaint(hWnd, &ps);函数,则此函数只做了两件事:填充ps结构、使窗口重新变得有效。另外DefWindowProc函数也会使窗口变得有效

关于ps.fErase;

这个参数和窗口函数WndProc的返回值有关:

当窗口函数WndProc返回true;则产生WM_PAINT消息时,ps.fErase就为false;表明系统擦除了背景

当窗口函数WndProc返回false;则产生WM_PAINT消息时,ps.fErase就为true;表明系统没有擦除背景

设想一下,当上面的代码中添加了WM_ERASEBKGND消息并在其中直接返回true(这表明系统已经绘制了窗口背景),则ps.fErase就为false

case WM_ERASEBKGND:

return true; //窗口函数WndProc返回true;

注意返回的真或者假只是让程序员可以看见ps.fErase,并作出自己的代码,与窗口的显示即背景没有关系

有些人说当ps.fErase==true,BeginPaint函数会发送一个WM_ERASEBKGND消息,其实BeginPaint并未发出WM_ERASEBKGND消息

4.自己绘制背景或者系统绘制背景。

如果程序员不想系统擦除背景,而自己想绘制背景,怎么办呢?方法是在WM_ERASEBKGND消息处理中添加自己的绘制代码。

对于WM_ERASEBKGND消息,wParam参数保存了用于绘制的设备环境,lParam不使用。

如上面的示例代码,当添加了WM_ERASEBKGND消息,则switch---case中就不会调用DefWindowProc函数绘制背景。这时,程序员自己就可以添加绘制代码,而在基于MFC的程序中,是这样处理自绘代码的:

BOOL CCeDlg::OnEraseBkgnd(CDC* pDC) //这个函数就是WM_ERASEBKGND的消息处理函数

{

// TODO: Add your message handler code here and/or call default

//添加自绘代码

...

return TRUE; //返回真,代表着窗口函数的返回值。以便于程序员在WM_PAINT消息中作出相应处理(如果需要)。这里返回时就不会调用下面的默认处理

//下面将调用系统默认的消息处理函数DefWindowProc进行背景的默认绘制。

return CDialog::OnEraseBkgnd(pDC); //不执行自动生成的这个函数

}

执行这个函数时,提示用户绘制背景,如果用户没有绘制背景,则return CDialog::OnEraseBkgnd(pDC);调用默认的窗口处理函数进行背景的擦除


5.WM_ERASEBKGND消息和WM_PAINT消息的另外一种含义:背景色与前景色

WM_ERASEBKGND消息用于通知系统或者程序员绘制背景色

WM_PAINT消息用于通知程序员绘制前景色,比如在WM_PAINT中调用TextOut函数输出文本

文章来自:http://blog.csdn.net/sdeeds/article/details/6859530

分享到:
评论

相关推荐

    系统 WM_ 消息列表及说明

    本文将深入解析一系列WM_消息,这些消息对于理解和实现Windows应用程序至关重要。 #### WM_NULL (0x0000) 这是一个空消息,通常用于测试或调试目的,不携带任何数据。 #### WM_CREATE (0x0001) 此消息在窗口创建时...

    BCB 實作無框透明背景文字範例

    【BCB实现无框透明背景文字范例】是关于C++ Builder(BCB)编程的一个技术主题,主要探讨如何在BCB环境中创建一个具有透明背景和文字的无边框窗口。在Windows应用程序开发中,这样的设计可以提供更美观、更符合用户...

    MFC 之 CButton 控件重绘(GDI+篇)

    在实际项目中,你可能还需要处理WM_ERASEBKGND消息,以避免系统默认的背景清除导致的闪烁。同时,可能需要处理WM_PAINT消息以确保按钮在被其他窗口覆盖后能正确更新。 在提供的"TestingBed"文件中,可能包含了一个...

    VC++做异形窗口 透明效果

    }接下来是在WM_PAINT的消息处理函数OnPaint()中添加代码。由于当背景位图比较大时,进行区域处理比较耗时,所以只在启动时进行一次处理。一种方法是OnInitDialog()处理,但这样会在从启动程序到窗口出现有相当的延迟...

    PB开发工具下SendMessage函数完全使用手册

    PB开发工具下SendMessage函数完全使用手册 SendMessage 函数是 Windows 消息机制中的一...通过理解 SendMessage 函数和其相关的消息类型,可以帮助开发者更好地掌握 Windows 消息机制,提高应用程序的性能和稳定性。

    C++所有WM消息总览表.doc

    ### C++ WM消息总览及解析 #### 一、引言 在Windows编程中,**WM消息**扮演了至关重要的角色。它们是Windows系统用于...希望本文的解析能够帮助开发者更好地理解和应用这些消息,从而提升应用程序的质量和用户体验。

    BCB实现MDI程序背景图

    总的来说,实现BCB中MDI程序的背景图显示,关键在于理解Windows的消息机制和钩子函数的使用,通过处理WM_PAINT和WM_ERASEBKGND消息,能够在MDI客户窗口上绘制自定义的背景图像,提升程序的视觉效果。同时,需要注意...

    VC界面美化

    最近看的一篇文章,感觉对于学习VC界面设计跟美化都很有用,所以稍作... 3.3.2 WM_ERASEBKGND 3.3.3 WM_CTLCOLOR 3.3.4 WM_DRAWITEM 3.3.5 WM_MEASUREITEM 3.3.6 NM_CUSTOMDRAW 3.4 使用MFC类的虚函数机制

    window消息说明

    - `WM_PAINT`:请求窗口进行重画。 - `WM_CLOSE`:当用户尝试关闭窗口或应用程序时发送。 - `WM_QUERYENDSESSION`和`WM_ENDSESSION`:在系统即将关闭或退出时发送,允许应用程序保存数据并清理资源。 - `WM_QUIT`:...

    Window 消息大全

    - **WM_ERASEBKGND** ($0014): 当窗口背景必须被擦除时发送此消息(例如窗口改变大小时)。 - **WM_SYSCOLORCHANGE** ($0015): 当系统颜色改变时,发送此消息给所有顶级窗口。 - **WM_ENDSESSION** ($0016): 在系统...

    Window消息大全

    此外,Window 消息大全还包括了许多其他的 Window 消息,如 WM_PAINT、WM_CLOSE、WM_QUERYENDSESSION、WM_QUIT、WM_QUERYOPEN、WM_ERASEBKGND、WM_SYSCOLORCHANGE、WM_ENDSESSION、WM_SHOWWINDOW、WM_ACTIVATEAPP、...

    禁止list control的水平滚动条

    ### 禁止List Control的水平滚动条 在Windows编程中,经常需要对窗口的一些行为进行自定义控制,比如禁止滚动条的...同时,理解不同的`WM`消息有助于我们更好地控制窗口的行为,并为用户提供更加流畅和直观的体验。

    Windows消息大全

    13. WM_ERASEBKGND:窗口背景需要擦除时发送,可以自定义背景绘制。 14. WM_SYSCOLORCHANGE:系统颜色改变,影响所有顶级窗口的外观。 15. WM_SHOWWINDOW:窗口显示或隐藏时发送。 16. WM_FONTCHANGE:系统字体库...

    WM消息大全

    通过对WM消息的理解和处理,开发者能够实现丰富的用户界面功能和应用逻辑控制。以下是对部分WM消息及其功能的详细解释。 #### WM_NULL($0000) - **含义**:空消息,通常用于测试目的。 - **应用场景**:当需要...

    win32环境下的按钮重绘

    3. 在窗口过程函数中处理`WM_PAINT`消息,使用`CreateCompatibleBitmap`和`SelectObject`等函数加载并绘制位图到按钮上。 4. 可以选择处理`WM_SETIMAGE`消息以动态改变按钮的图像。 5. 处理`WM_NCPAINT`消息以自定义...

    vc++ 窗体透明

    当涉及到透明效果时,关键在于处理WM_PAINT和WM_ERASEBKGND消息。默认情况下,这两个消息会填充窗体背景并绘制边框,但为了实现透明,我们需要自定义这些处理过程。 1. **创建透明窗体**: 在创建窗体时,可以通过...

    VS2010-MFC编程入门

    17. WM_ERASEBKGND:窗口背景需要擦除时触发,如窗口大小调整。 18. WM_SYSCOLORCHANGE:系统颜色改变时触发。 19. WM_SHOWWINDOW:窗口显示或隐藏时触发。 20. WM_ACTIVATEAPP:应用程序激活或非激活状态改变时触发...

    SendManage

    16. `WM_ERASEBKGND`: 当需要擦除窗口背景时发送。 17. `WM_SYSCOLORCHANGE`: 系统颜色改变时发送,影响使用系统颜色的控件。 18. `WM_SHOWWINDOW`: 控制窗口的隐藏和显示。 19. `WM_WININICHANGE` 和 `WM_...

    改变树控件背景颜色的VC源代码

    4. **在OnPaint中绘制**:虽然`WM_ERASEBKGND`可以处理大部分情况,但在某些特殊情况下(如滚动或重绘),可能还需要在`OnPaint`消息处理函数中使用`BeginPaint`和`EndPaint`进行绘制。 以下是一个简单的示例代码,...

Global site tag (gtag.js) - Google Analytics