c++ WM_PAINT

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了c++ WM_PAINT相关的知识,希望对你有一定的参考价值。

c++ win32
响应WM_PAINT时,为什么必须用BeginPaint来获取dc,能不能用GetDC,这两种有什么区别

#include <windows.h>
HINSTANCE g_hInstance;
void myDraw(HWND hwnd,HDC dc)

RECT rect;
GetClientRect(hwnd, &rect);
HDC hdcmem=::CreateCompatibleDC(dc);

HBITMAP hbitmap=::CreateCompatibleBitmap(dc,rect.right,rect.bottom);
::SelectObject(hdcmem,hbitmap);
::FillRect(hdcmem,&rect,NULL);
::Rectangle(hdcmem,0,0,rect.right,rect.bottom);
::BitBlt(dc,0,0,rect.right,rect.bottom,hdcmem,0,0,SRCCOPY);
::DeleteObject(hbitmap);
::DeleteDC(hdcmem);


LRESULT CALLBACK WindowProc(HWND hwnd,
UINT uMsg,
WPARAM wParam,
LPARAM lParam)

switch(uMsg)


case WM_PAINT:
HDC dc;
dc=::GetDC(hwnd);//如果这里用BeginPaint来获取dc,运行的结果就差太多了
myDraw(hwnd,dc);
::ReleaseDC(hwnd,dc);
break;

case WM_DESTROY:
PostQuitMessage(0);
break;

default:
return DefWindowProc(hwnd,uMsg,wParam,lParam);


return 0;


int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)

g_hInstance=hInstance;
WNDCLASS wndcls;
wndcls.cbClsExtra=0;
wndcls.cbWndExtra=0;
wndcls.hIcon=NULL;
wndcls.lpszMenuName=NULL;
wndcls.hbrBackground=NULL;
wndcls.hInstance=hInstance;
wndcls.lpfnWndProc=WindowProc;
wndcls.hCursor=LoadCursor(NULL,IDC_ARROW);
wndcls.lpszClassName="Window";
wndcls.style=CS_DBLCLKS;
RegisterClass(&wndcls);

HWND hwnd;
hwnd=CreateWindow("Window","",WS_OVERLAPPEDWINDOW,100,100,400,300,NULL,NULL,hInstance,NULL);

ShowWindow(hwnd,SW_SHOWNORMAL);

MSG msg;
while(GetMessage(&msg,NULL,0,0))

TranslateMessage(&msg);
DispatchMessage(&msg);

return 0;

请高人指点

参考技术A

  第一种情况显示出来的字很正常。

case WM_PAINT: 
           gdc = BeginPaint (hwnd, &ps); 
           TextOut (gdc, 0, 0, s, strlen (s)); 
           break;

  第二种情况显示 的字不停闪烁。

case WM_PAINT: 
           gdc = GetDC (hwnd);
           TextOut (gdc, 0, 0, s, strlen (s)); 
           ReleaseDC (hwnd, gdc); 
break;

  原因在于:

  BeginPaint() 和EndPaint() 可以删除消息队列中的WM_PAINT消息,并使无效区域有效。
GetDC()和 ReleaseDC()并不删除也不能使无效区域有效,因此当程序 跳出 WM_PAINT 时 ,无效区域仍然存在。系统 就回不断发送WM_PAINT消息,于是程序不断处 理WM_PAINT消息。
BeginPaint、 EndPaint会告诉GDI内部,这个窗口 需要重画的地方已经重画了,这样WM_PAINT处 理完返回给系统后,系统不会再重发WM_PAINT,而GetDC没有告诉系统这个窗口需要重画的地方已经画过,在你把程序返回给系统后,系统一直以为通 知你的重画命令你还没有乖乖的执行或者执行出错,所以在消息空闲时,它还会不断地发WM_PAINT催促你画,导致程序卡死。


无效区域就是指需要重画的区域,无效的意思是:当前内容是旧的,过时的。 
假设A是新弹出的一个对话框或被 激活的现有对话框,A对话框置于原来的活动 对话框B前面,造成对话框B的部分或全部被覆盖,当 对话框A移开或关闭后,使对话框B原来被覆盖的地方重新可见。那部分被覆盖的地方就称为无效区域。 
只 有当一个窗口消息空闲时,系统才会抽空检查一下这个窗口的无效区域是否为非空(WM_PAINT的优先级是最低的。这也就是为什么系统很忙时窗口和桌面往 往会出现变白、刷新不了、留拖拽痕迹等现象的原因),如果非空,系统就发送WM_PAINT。所以一定要用BeginPaint、EndPaint把无效 区域设为空,否则WM_PAINT将一直被发送。

本回答被提问者和网友采纳

WM_PAINT消息详解,使用InvalidateRect或InvalidateRgn函数刻意产生WM_PAINT消息(WIN7里有变化,“调整视觉效果”,将“启用桌面组合”去掉)

什么时候会触发WM_PAINT消息消息呢?

以下内容来自大名鼎鼎的《Windows程序设计(第五版)》

大多数Windows程序在WinMain中进入消息循环之前的初始化期间都要呼叫函数UpdateWindow。Windows利用这个机会给窗口消息处理程序发送第一个WM_PAINT消息。这个消息通知窗口消息处理程序:必须绘制显示区域。此后,窗口消息处理程序应在任何时刻都准备好处理其它WM_PAINT消息,必要的话,甚至重新绘制窗口的整个显示区域。在发生下面几种事件之一时,窗口消息处理程序会接收到一个WM_PAINT消息:

  • 在使用者移动窗口或显示窗口时,窗口中先前被隐藏的区域重新可见。
     
  • 使用者改变窗口的大小(如果窗口类别样式有着CS_HREDRAW和CS_VREDRAW位旗标的设定)。
     
  • 程序使用ScrollWindow或ScrollDC函数滚动显示区域的一部分。
     
  • 程序使用InvalidateRect或InvalidateRgn函数刻意产生WM_PAINT消息。
     

在某些情况下,显示区域的一部分被临时覆盖,Windows试图保存一个显示区域,并在以后恢复它,但这不一定能成功。在以下情况下,Windows可能发送WM_PAINT消息:

  • Windows擦除覆盖了部分窗口的对话框或消息框。
     
  • 菜单下拉出来,然后被释放。
     
  • 显示工具提示消息。
     

在某些情况下,Windows总是保存它所覆盖的显示区域,然后恢复它。这些情况是:

  • 鼠标光标穿越显示区域。
     
  • 图标拖过显示区域。

 

 

但实际上,在win7下编写的程序,有可能遇到下面的情况:

当把程序窗口最大化时,触发WM_PAINT消息;当移动窗口时,有时会触发WM_PAINT消息,有时不会触发;而当其他窗口遮挡程序的窗口时,一定不会发出WM_PAINT消息,这又是为什么呢?

其实这跟你的windows7的设置有关,在“控制面板”的“性能信息和工具”一栏中,选择“调整视觉效果”,将“启用桌面组合”去掉,就可以了。

当触发WM_PAINT消息时,就会准备处理整个区域。可实际上,系统只是重绘无效区。比如,当你把窗口A从窗口B上移开时,不是整个重绘窗口B,而是,B的其他部分不动,只是重绘漏出来的部分。要是你想整个重绘,需要使用InvalidateRect (hwnd, NULL, TRUE)指明无效区是整个客户区。

 

那么WM_PAINT消息该如何使用呢?

windows绘图,是通过GDI(图形设备接口)完成。简单的说,GDI是由:DC(设备描述表),GDI函数,GDI基本图形和一些其他的东西组成的。要想使用GDI绘图,必须拿到DC。因为DC与特定的显示(打印设备相关)。只有拿到了DC,才能正确的输出图形。举一个简单的例子,光栅设备(简单的说,就是显示的时候以像素为单位的)和矢量设备(显示的时候,告诉他起点和终点,它会给你自动连线的)的成像原理不同,所以只有知道了他们的成像原理(DC里面有),才能画图。

那么怎么拿到DC呢,方法很多,但是在WM_PAINT消息下,只能使用BeginPaint获取hdc,用完之后使用EndPaint释放它。在二者之间写GDI函数。即使你在WM_PAINT消息下什么都不做,也得写上这两句。原因是因为WM_PAINT会导致无效区域的背景被擦除。

http://blog.csdn.net/thefutureisour/article/details/7533497

以上是关于c++ WM_PAINT的主要内容,如果未能解决你的问题,请参考以下文章

C++之父的C++元宇宙

[C++]C++入门到入土篇 HelloWorld 解析 && C++入门

怎么找C++函数需要的头文件?(C++头文件C++函数文档C++文档)

如何识别项目是托管 c++ 项目还是非托管 c++ 项目

C++ 程序员应该使用哪些 C++ 习语? [关闭]

十类C++标准库 十类C++标准库简介