[英]WINapi. Can't erase background of window with ellipse
我只是想繪制一個橢圓:
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);
}
}
你的代碼沒有刪除任何東西。 它只是在指定的坐標處繪制一個橢圓。 之前繪制的橢圓仍然存在。
你提到了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); }
現在,除非您從case
標簽內部明確return
,否則每次都會調用默認窗口過程。
當您注冊窗口類(在MyRegisterClass
)時,您將WNDCLASS
結構的所有字段歸零,然后顯式初始化其中的幾個字段。 您沒有顯式初始化hbrBackground
字段,因此它被設置為0.當hbrBackground
為0時,
當此成員為
NULL
,應用程序必須在請求在其客戶區域中繪制時繪制其自己的背景。 要確定是否必須繪制背景,應用程序可以處理WM_ERASEBKGND
消息或測試由BeginPaint
函數填充的PAINTSTRUCT
結構的fErase
成員。
這意味着默認窗口過程沒有響應WM_ERASEBKGND
消息,因為您沒有為窗口提供背景畫筆。
您需要將hbrBackground
設置為COLOR_WINDOW + 1
,或者您需要將代碼添加到WM_ERASEBKGND
消息處理程序中以COLOR_WINDOW + 1
擦除窗口的背景。
或者,或許更好的選擇是完全忘記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;
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.