除了wm_erasebkgnd会擦除背景,还有什么消息会擦出背景

liulin2025 2013-02-04 02:53:20

wm_create:

getdc
movetoex
lineto
releasedc

return 0;
break;


wm_erasebkgnd: //这里特殊处理了
return 1; //简单的返回,让其不要擦出背景。

break;

但是 并没有看到 wm_create里绘制的直线, 怎么回事???


因为wm_erasebkgnd会擦背景的, 如果我们直接诶返回true.那么它就不会了,既然没有擦出背景那么我们的

wm_create里的曲线就应该存在啊? 因为没有睡去擦出客户区域啊

事实并非如此。

除了wm_erasebkgnd会擦除背景,还有什么消息会擦出背景????


[/code]
...全文
402 12 打赏 收藏 转发到动态 举报
写回复
用AI写文章
12 条回复
切换为时间正序
请发表友善的回复…
发表回复
rxguoblp 2013-02-04
  • 打赏
  • 举报
回复
就一句话:楼主画线代码的位置不对,应该在OnPaint()函数里面。
wzuxian2012 2013-02-04
  • 打赏
  • 举报
回复
引用 10 楼 wocow3 的回复:
缩进没了。。。 我的意思是BeginPaint()的内部实现包含if(need erasebkgnd) SendMessage(WM_ERASEBKGND)的代码
准确地说: 窗口刚创建时候, wm_eraskbkgnd 在wm_paint之前 后来,才可以用你的 伪代码来表示 你的伪代码不完整。
wocow3 2013-02-04
  • 打赏
  • 举报
回复
缩进没了。。。 我的意思是BeginPaint()的内部实现包含if(need erasebkgnd) SendMessage(WM_ERASEBKGND)的代码
wocow3 2013-02-04
  • 打赏
  • 举报
回复
WM_PAINT与WM_ERASEBKGNDWM_PAINT严格的说是一个包含关系,用“前后”描述并不准确 具体流程是 WM_PAINT消息处理函数的标准流程: BeginPaint() → if(need erasebkgnd) → SendMessage(WM_ERASEBKGND) your code EndPaint() 也就说WM_ERASEBKGND是BeginPaint()触发调用的的,当BeginPaint返回,背景已经擦除
bsnry 2013-02-04
  • 打赏
  • 举报
回复
引用 5 楼 schlafenhamster 的回复:
不管画什么,一定是 窗口 有效 后画上去的 才能 保留,窗口 无效时 画什么 都会被 擦除。 Create 时 窗口 还处于无效。
++ 可以放在wm_size里, 此时窗口可以绘制了, 测试代码:
	switch (message) 
	{
	case	WM_ERASEBKGND:
		return TRUE;
		break;

	case WM_SIZE:
		{

			HDC hdc=GetDC(hWnd);
			MoveToEx(hdc,20,20,NULL);
			LineTo(hdc,100,200);
			ReleaseDC(hWnd,hdc);
		break;
		}

		return 0;

		case WM_PAINT:
			hdc = BeginPaint(hWnd, &ps);
			// TODO: Add any drawing code here...
			RECT rt;
			GetClientRect(hWnd, &rt);
			DrawText(hdc, szHello, strlen(szHello), &rt, DT_CENTER);
			EndPaint(hWnd, &ps);
			break;
wm_erasebkgnd不擦除背景的话, 如果wm_piant也不擦除, 是比较糟糕的做法, 窗口一旦变化,那么就会留下很多阴影.
信阳毛尖 2013-02-04
  • 打赏
  • 举报
回复
你首先要搞清楚WM_CREATE(Create)和 WM_PAINT(OnPaint)都是用来干什么的呀 Create只是创建,所有的UI(GetDC()处理的除外)都是在 OnPaint中完成的,
Eleven 2013-02-04
  • 打赏
  • 举报
回复
把你绘图的操作放到WM_PAINT消息响应函数OnPaint()中去做
schlafenhamster 2013-02-04
  • 打赏
  • 举报
回复
不管画什么,一定是 窗口 有效 后画上去的 才能 保留,窗口 无效时 画什么 都会被 擦除。 Create 时 窗口 还处于无效。
sumos 2013-02-04
  • 打赏
  • 举报
回复
从来都是 WM_ERASEBKGND在先,WM_PAINT在后。 只是有时候,没有WM_ERASEBKGND。 比如Invalidate(FALSE); //参数表示是否发送WM_ERASEBKGND
bsnry 2013-02-04
  • 打赏
  • 举报
回复
引用 1 楼 zhoujielunzhimi 的回复:
虽然你在WM_CREATE的时候画了线,但是后面真正绘制的地方是WM-PAINT,默认的WM-PAINT会填充客户区域,你的画线自然就消失了。
引用 2 楼 sha_jinhao 的回复:
一直以来,对于WM_PAINT和WM_ERASEBKGND消息不是很清楚,从书上和网上找了很多资料,大体上有以下几点说法: 1>WM_PAINT先产生,WM_ERASEBKGND后产生 2.WM_PAINT产生后,在调用BeginPaint时 hdc = BeginPaint(hWnd, &ps); 如果ps.fErase为true,则BeginPa……
一直以来,对于WM_PAINT和WM_ERASEBKGND消息不是很清楚,从书上和网上找了很多资料,大体上有以下几点说法: 1>WM_PAINT先产生,WM_ERASEBKGND后产生 原来 ,这个段子一直以来都被讹传了。 日志打印看看, 谁在先,谁在后? 又或者顺序时而在先,时而在后?
jimette 2013-02-04
  • 打赏
  • 举报
回复
一直以来,对于WM_PAINT和WM_ERASEBKGND消息不是很清楚,从书上和网上找了很多资料,大体上有以下几点说法: 1>WM_PAINT先产生,WM_ERASEBKGND后产生 2.WM_PAINT产生后,在调用BeginPaint时 hdc = BeginPaint(hWnd, &ps); 如果ps.fErase为true,则BeginPaint会产生WM_ERASEBKGND消息 3.BeginPaint函数用来擦除窗口背景 4.WM_ERASEBKGND用来绘制背景 经过调试、分析,发现上面的说法并不正确。以下是一些测试代码,代码后面附上一些分析。最后总结出几点,可以解释程序中出现的所有关于窗口重绘的问题。 如有不正确的地方,大家可以指正。 为了说明问题,在此不说WM_NCPAINT消息(非客户区消息),只说WM_ERASEBKGND消息和客户区的WM_PAINT消息 //此段代码摘自vc6应用程序向导自动生成的代码,并添加了一些测试代码 LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; TCHAR szHello[MAX_LOADSTRING]; LoadString(hInst, IDS_HELLO, szHello, MAX_LOADSTRING); switch (message) { case WM_COMMAND: wmId = LOWORD(wParam); wmEvent = HIWORD(wParam); // Parse the menu selections: switch (wmId) { case IDM_ABOUT: DialogBox(hInst, (LPCTSTR)IDD_ABOUTBOX, hWnd, (DLGPROC)About); break; case IDM_EXIT: DestroyWindow(hWnd); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } break; case WM_ERASEBKGND: //如果处理了这个消息,则默认消息处理函数不会调用,背景就不会绘制 { static int iCount=0; char ch[MAX_PATH]; sprintf(ch,"%d ---------WM_ERASEBKGND\n",iCount); //这个函数需要包含#include<stdio.h> OutputDebugString(ch); //调试时便于观察 iCount++; break; } case WM_PAINT: { OutputDebugString(" -------------WM_PAINT\n"); hdc = BeginPaint(hWnd, &ps); //使无效区域变得有效,并填充ps结构 // TODO: Add any drawing code here... //绘制一个蓝色椭圆,ps.rcPaint保存了客户区矩形 HBRUSH hbrush=::CreateSolidBrush(RGB(0,0,255)); ::SelectObject(hdc,hbrush); ::Ellipse(hdc,ps.rcPaint.left,ps.rcPaint.top,ps.rcPaint.right,ps.rcPaint.bottom); ::DeleteObject(hbrush); EndPaint(hWnd, &ps); break; } case WM_LBUTTONDOWN: //调用DefWindowProc擦除客户区背景 { HDC hdc; hdc=::GetDC(hWnd); WPARAM w=(WPARAM)hdc; LPARAM l=0; DefWindowProc(hWnd, WM_ERASEBKGND, w, l); } break; case WM_DESTROY: PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } return 0; } 先说一下程序运行时发现的一些现象: 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消息) 1》填充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);调用默认的窗口处理函数进行背景的擦除 BOOL CCeDlg::OnEraseBkgnd(CDC* pDC) { // TODO: Add your message handler code here and/or call default //添加自绘背景代码 CBitmap m_bitmap; BITMAP m_bmInfo; m_bitmap.LoadBitmap(IDB_BITMAP1); m_bitmap.GetObject(sizeof(m_bmInfo),&m_bmInfo); CDC memDC; memDC.CreateCompatibleDC(pDC); memDC.SelectObject(&m_bitmap); GetClientRect(m_rect); pDC->StretchBlt(0,0,m_rect.Width(),m_rect.Height(), &memDC,0,0,m_bmInfo.bmWidth,m_bmInfo.bmHeight,SRCCOPY); //内存拷贝函数。绘制背景 memDC.DeleteDC(); return true;//返回真,代表着窗口函数的返回值。以便于程序员在WM_PAINT消息中作出相应处理(如果需要)。这里返回时就不会调用下面的默认处理 //下面将调用系统默认的消息处理函数DefWindowProc进行背景的默认绘制。 return CDialog::OnEraseBkgnd(pDC); //不执行自动生成的这个函数 } 5.WM_ERASEBKGND消息和WM_PAINT消息的另外一种含义:背景色与前景色 可以这样理解WM_ERASEBKGND消息和WM_PAINT消息: WM_ERASEBKGND消息用于通知系统或者程序员绘制背景色 WM_PAINT消息用于通知程序员绘制前景色,比如在WM_PAINT中调用TextOut函数输出文本
sumos 2013-02-04
  • 打赏
  • 举报
回复
虽然你在WM_CREATE的时候画了线,但是后面真正绘制的地方是WM-PAINT,默认的WM-PAINT会填充客户区域,你的画线自然就消失了。

16,548

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC相关问题讨论
社区管理员
  • 基础类社区
  • AIGC Browser
  • encoderlee
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告

        VC/MFC社区版块或许是CSDN最“古老”的版块了,记忆之中,与CSDN的年龄几乎差不多。随着时间的推移,MFC技术渐渐的偏离了开发主流,若干年之后的今天,当我们面对着微软的这个经典之笔,内心充满着敬意,那些曾经的记忆,可以说代表着二十年前曾经的辉煌……
        向经典致敬,或许是老一代程序员内心里面难以释怀的感受。互联网大行其道的今天,我们期待着MFC技术能够恢复其曾经的辉煌,或许这个期待会永远成为一种“梦想”,或许一切皆有可能……
        我们希望这个版块可以很好的适配Web时代,期待更好的互联网技术能够使得MFC技术框架得以重现活力,……

试试用AI创作助手写篇文章吧