WM_PAINT 问题

h2plus0 2012-07-22 03:02:25
请问为什么下面的程序会出现一些区域 没有重绘 的现象(灰色的区域)?

重现步骤:
运行下面程序, 最大化
运行另外一个程序,比如计算器, 移动计算器窗口
就会出现 灰色区域 (最好快速拖动计算器窗口,比较容易重现)




// vcwin32.cpp : Defines the entry point for the application.
//

#include "stdafx.h"
#include "vcwin32.h"

//---------------------------------------------------------------------------
#include <windows.h>
#include <winuser.h>
#include <commctrl.h>
#include <tchar.h>

#include <assert.h>

HINSTANCE ghInstance;// Global Instance

// Prototyp WindowFunction
LRESULT CALLBACK WndProcedure (HWND hwnd, UINT msg,WPARAM w, LPARAM l);
//****************************************************************************************

HWND mainWin;

int WINAPI _tWinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPTSTR /*lpCmdLine*/, int nCmdShow)
{
//InitCommonControls();
static TCHAR szAppName[]= __TEXT("Test_WmPaint");
static TCHAR szTitleBar[]= __TEXT("Title Bar");

WNDCLASSEX wndclass;
MSG msg;

// Register Class
ghInstance = hInstance;

wndclass.cbSize = sizeof(WNDCLASSEX);
wndclass.style = CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS ;
wndclass.lpfnWndProc = WndProcedure;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = NULL;//LoadIcon (ghInstance, IDI_APPLICATION);
wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);

//wndclass.hbrBackground = Null;
//wndclass.hbrBackground = CreateSolidBrush(RGB(200,0,0));
wndclass.hbrBackground = (HBRUSH)(COLOR_GRAYTEXT+1);//GetStockObject (WHITE_BRUSH);

wndclass.lpszMenuName = NULL;
wndclass.lpszClassName = szAppName;
wndclass.hIconSm = NULL;//LoadIcon(NULL, IDI_APPLICATION);

if (!RegisterClassEx (&wndclass)) {
MessageBox(NULL, __TEXT("Window Registration Failed!"), __TEXT("Error!"), MB_ICONEXCLAMATION | MB_OK);
return -1;
}

// Create Window and show Window
mainWin = CreateWindow (szAppName,
szTitleBar,
WS_OVERLAPPEDWINDOW, //WS_POPUP, //!WS_CAPTION ,
200, // x position for this window
200, // y position for this window
300, // window width
300, // window height
NULL, // parent
NULL, // menu
hInstance,
NULL); // user data

if (mainWin == NULL) {
MessageBox(NULL, __TEXT("Window Creation Failed!"), __TEXT("Error!"),MB_ICONEXCLAMATION | MB_OK);
return 0;
}

ShowWindow (mainWin, nCmdShow);
UpdateWindow (mainWin);

// Dispatch Message or exit program
while (GetMessage (&msg, NULL, 0, 0)) {
//if(!IsDialogMessage(hwnd, &msg)){
TranslateMessage (&msg);
DispatchMessage (&msg);
//}
}
return (msg.wParam);
}

//**************************************************************************

HBRUSH brushes[] = {
CreateSolidBrush(RGB(100,0,0)),
CreateSolidBrush(RGB(0,160,0)),
CreateSolidBrush(RGB(0,0,255)),
};

LRESULT CALLBACK WndProcedure (HWND hWnd, UINT wMsg, WPARAM wParam, LPARAM lParam)
{
static int x=0;
assert(hWnd!=NULL);
int ret=0;

HDC hdc=NULL;
//HPEN pen=NULL;
PAINTSTRUCT ps;
RECT rt;
SetRect(&rt,0,0,0,0); // init

switch (wMsg) {
case WM_CREATE:
break;


case WM_LBUTTONDOWN:
return 0;
/*
hdc = GetDC(hWnd);

GetClientRect(hWnd, &rt);
FillRect(hdc, &rt, brushes[0]);
ReleaseDC(hWnd, hdc);
break;
*/

case WM_PAINT:{
x++;

hdc = BeginPaint(hWnd, &ps);
rt = ps.rcPaint;

SetRect(&rt, 0,0,2000,2000);
//use this line can easy see which region is painted.
ret=FillRect(hdc, &rt/*&ps.rcPaint*/, brushes[x%2]);
//ret=FillRect(hdc, &ps.rcPaint, brushes[0]);
if(ret==0) {
MessageBox(mainWin, __TEXT("fill rect Error "), __TEXT("Error"), MB_OK);
}

//RedrawWindow(hWnd, &ps.rcPaint, NULL, RDW_NOERASE);
EndPaint(hWnd, &ps);

//GdiFlush ();
return 0;
}

case WM_ERASEBKGND:
hdc = (HDC)wParam;

rt.left = 0 ; rt.top = 0;
rt.right = 300; rt.bottom = 300;
ret=FillRect(hdc, &rt, brushes[2] );
return 1;

case WM_DESTROY:
PostQuitMessage (0);
return (0);
}
return DefWindowProc (hWnd, wMsg, wParam, lParam);
}






...全文
170 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
h2plus0 2012-07-22
  • 打赏
  • 举报
回复
如果:
需要在 BeginPaint() 前调用 InvalidateRect(hWnd,NULL, TRUE),
那样相当于重绘整个窗口 , 理论上应该只用重绘:
PAINTSTRUCT.rcPaint 区域啊,

这还是最简化的窗口,
如果对每个窗口都 双缓冲, 重绘整个窗口 , 那样对性能会有影响啊


[Quote]
可以在BeginPaint前 InvalidateRect(hWnd, NULL, TRUE)
[/Quote]
长尾巴的悟空 2012-07-22
  • 打赏
  • 举报
回复
你选择一片区域重绘试试,就知道哪出问题了。
h2plus0 2012-07-22
  • 打赏
  • 举报
回复
谢谢回复, 但即使是改成所示代码, 在俺的机器上, 移动其他窗口时还是会
出现灰色的区域, 即 没有重绘

俺还叫一个使用vista的朋友运行过, 但运行结果有点奇怪, 居然只会显示一种颜色,绿色。。。
非常确定当时运行的是这一句:
ret=FillRect(hdc, &rt/*&ps.rcPaint*/, brushes[x%2]);
结果应该时 红色 和 绿色 交替 的呀
然道跟系统有关, 俺的系统是 xp, sp3


[Quote=引用 1 楼 的回复:]

1 背景填充没有包含所有客户区
C/C++ code

case WM_ERASEBKGND:
hdc = (HDC)wParam;
GetClientRect(hWnd, &rt);
//rt.left = 0 ; rt.top = 0;
//rt.right = 300; rt.bot……
[/Quote]
zgl7903 2012-07-22
  • 打赏
  • 举报
回复
1 背景填充没有包含所有客户区

case WM_ERASEBKGND:
hdc = (HDC)wParam;
GetClientRect(hWnd, &rt);
//rt.left = 0 ; rt.top = 0;
//rt.right = 300; rt.bottom = 300;
ret=FillRect(hdc, &rt, brushes[2] );
return 1;


2 WM_PAINT 中 BeginPaint 会自动裁剪刷新区域,因此导致不能刷新其它区域,
可以在BeginPaint前 InvalidateRect(hWnd, NULL, TRUE) 这样就会全部刷新
推荐使用双缓冲贴图的方法,还可以解决闪烁的问题
h2plus0 2012-07-22
  • 打赏
  • 举报
回复
[Quote=引用 6 楼 的回复:]

在vista和win7上运行是一种颜色,出不来你说的效果。
默认的aero主题不会像你想的那样去重绘。
win7下把界面主题改成Windows经典就可以测试你的程序了。
我在win7下测试了一下,没有出现你说的没有重绘的问题。
[/Quote]

谢谢回复! 原来真的是跟 外观 设置有关啊,在 xp 上面,
如果使用 经典window 外观, 就会出现 没有 重绘的区域
如果使用 xp 样式 外观 , 就不会出现 没有 重绘的区域 ,显示的 是 交替的 红色 或 绿色

如果代码是执行的是:ret=FillRect(hdc, &rt/*&ps.rcPaint*/, brushes[x%2]);
不太清楚为什么vista上只显示一种颜色,应该显示 交替的 红色 或 绿色 啊

谢谢大家!
hyqok 2012-07-22
  • 打赏
  • 举报
回复
在vista和win7上运行是一种颜色,出不来你说的效果。
默认的aero主题不会像你想的那样去重绘。
win7下把界面主题改成Windows经典就可以测试你的程序了。
我在win7下测试了一下,没有出现你说的没有重绘的问题。
壹只皮卡丘 2012-07-22
  • 打赏
  • 举报
回复
[Quote=引用 3 楼 的回复:]

你选择一片区域重绘试试,就知道哪出问题了。
[/Quote]对

15,979

社区成员

发帖
与我相关
我的任务
社区描述
VC/MFC 界面
社区管理员
  • 界面
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

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