簡體   English   中英

WINAPI。無法用橢圓擦除窗口的背景

[英]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消息,但有兩個原因導致你不能使用它:

  1. 在窗口過程( 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 ,否則每次都會調用默認窗口過程。

  2. 當您注冊窗口類(在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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM