我只想画一个椭圆:
case WM_PAINT:
hdc = BeginPaint(parentWindow, &ps);
Ellipse(hdc, x, y, width, height);
EndPaint(parentWindow, &ps);
,然后使用计时器每秒绘制一个带有一些新参数的新椭圆来擦除它:
case WM_CREATE:
SetTimer(hWnd, 1, 1000, NULL);
break;
case WM_TIMER:
x += 5;
InvalidateRect(hWnd, NULL, TRUE);
break;
但椭圆不会被删除和分层:
但是,我试图跟踪WM_ERASEBKGND,它确实是每个InvalidateRect发送的。
完整代码:
#include <Windows.h>
#include <windowsx.h>
#include <tchar.h>
#include <iostream>
TCHAR szWindowClass[] = TEXT("CreateThreadWindow");
TCHAR szAppName[] = TEXT("CreateThreadExample");
BOOL InitWindow(HINSTANCE, int);
ATOM MyRegisterClass(HINSTANCE);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HWND parentWindow;
MSG msg;
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
MyRegisterClass(hInstance);
if (!InitWindow(hInstance, nCmdShow))
return FALSE;
BOOL bRet;
while ((bRet = GetMessage(&msg, (HWND)NULL, 0, 0)) != 0)
{
if (bRet == -1)
return FALSE;
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASS wndClass;
memset(&wndClass, 0, sizeof(wndClass));
wndClass.lpfnWndProc = WndProc;
wndClass.hInstance = hInstance;
wndClass.lpszMenuName = NULL;
wndClass.lpszClassName = szWindowClass;
return RegisterClass(&wndClass);
}
BOOL InitWindow(HINSTANCE hInstance, int nCmdShow)
{
parentWindow = CreateWindow(szWindowClass, szAppName, WS_OVERLAPPEDWINDOW,
300, 0, 600, 600, NULL, NULL, hInstance, NULL);
ShowWindow(parentWindow, nCmdShow);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
{
PAINTSTRUCT ps;
HDC hdc;
static int x = 0, y = 0, width = 200, height = 100;
switch (message) {
case WM_ERASEBKGND:
_RPT1(0, "%s\n", "erase");
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
Ellipse(hdc, x, y, width, height);
EndPaint(hWnd, &ps);
break;
case WM_CREATE:
SetTimer(hWnd, 1, 1000, NULL);
break;
case WM_TIMER:
x += 5;
InvalidateRect(hWnd, NULL, TRUE);
break;
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hWnd, message, wparam, lparam);
}
}
答案 0 :(得分:5)
您的代码没有删除任何内容。它只是在指定的坐标处绘制一个椭圆。之前绘制的椭圆仍在那里。
您提到了WM_ERASEBKGND
消息,但有两个原因导致您无效:
在窗口过程(WndProc
)中,您显式处理WM_ERASEBKGND
消息,这意味着它不会传递给默认窗口过程(DefWindowProc
) 。编写窗口过程的更好方法如下:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wparam, LPARAM lparam)
{
static int x = 0, y = 0, width = 200, height = 100;
switch (message) {
case WM_ERASEBKGND:
{
_RPT1(0, "%s\n", "erase");
break;
}
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
Ellipse(hdc, x, y, width, height);
EndPaint(hWnd, &ps);
return 0;
}
case WM_CREATE:
{
SetTimer(hWnd, 1, 1000, NULL);
break;
}
case WM_TIMER:
{
x += 5;
InvalidateRect(hWnd, NULL, TRUE);
return 0;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
}
default:
break;
}
return DefWindowProc(hWnd, message, wparam, lparam);
}
现在,除非您从return
标签内明确case
,否则每次都会调用默认窗口过程。
当您注册窗口类(MyRegisterClass
内)时,将WNDCLASS
structure的所有字段归零,然后显式初始化其中的几个字段。您不显式初始化hbrBackground
字段,因此将其设置为0.当hbrBackground
为0时,
当此成员为
NULL
时,应用程序必须在请求在其客户区域中绘制时绘制自己的背景。要确定是否必须绘制背景,应用程序可以处理WM_ERASEBKGND
消息或测试fErase
函数填充的PAINTSTRUCT
结构的BeginPaint
成员。
这意味着默认窗口过程没有响应WM_ERASEBKGND
消息,因为您没有给窗口提供背景画笔。
您需要将hbrBackground
设置为COLOR_WINDOW + 1
之类的内容,否则您需要向WM_ERASEBKGND
消息处理程序添加代码以自行删除窗口的背景。
WM_ERASEBKGND
消息,正如许多Windows程序员所做的那样,因为这种两步擦除和绘制方法往往会导致闪烁。将hbrBackground
字段设置为NULL,不响应WM_ERASEBKGND
消息执行任何操作,并在WM_PAINT
处理程序的顶部执行删除操作:
case WM_PAINT:
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd, &ps);
// Erase background of entire client area.
RECT rcClient;
GetClientRect(hWnd, &rcClient);
FillRect(hdc, &rcClient, reinterpret_cast<HBRUSH>(COLOR_WINDOW+1));
// Do normal drawing.
Ellipse(hdc, x, y, width, height);
EndPaint(hWnd, &ps);
return 0;
}