2017-05-19 3 views
3

난 그냥 타원 그릴려고와 윈도우의 배경을 지울 수 없습니다 :WINapi. 타원

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; 

그러나 타원이 삭제되지 않고 계층 그러나

Ellipses

, 내가 그럴 필요하려 에이스 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 메시지를 처리에서

  1. 는이 있음을 의미 기본 창 프로 시저 (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); 
    } 
    

    이제 기본 창 절차는 때마다 호출되는하지 않는 한 명시 적으로 returncase 라벨의 내부에서합니다.

  2. MyRegisterClass의 창 클래스를 등록하면 WNDCLASS structure의 모든 필드가 0으로 설정되고 두 필드가 명시 적으로 초기화됩니다. 당신은하지 명시 적으로 hbrBackground 필드를 초기화 할 , 그래서 0으로 설정되고 그리고 hbrBackground 인 경우 0,

    이 멤버는 NULL입니다

    가, 자신의 배경을 페인트합니다 응용 프로그램이 그것으로 요청 될 때마다 클라이언트 영역에 페인트. 배경을 그려야하는지 여부를 결정하려면 응용 프로그램에서 WM_ERASEBKGND 메시지를 처리하거나 함수로 채워진 PAINTSTRUCT 구조의 구성원 인 fErase을 테스트 할 수 있습니다.

    이것은 당신의 창 배경 브러시를 제공하지 않았기 때문에 기본 창 프로 시저가 WM_ERASEBKGND 메시지에 대한 응답으로 아무것도하지 않는 것을 의미한다.

    hbrBackgroundCOLOR_WINDOW + 1과 같이 설정하거나메시지 처리기에 코드를 추가하여 창 배경을 직접 지워야합니다.

또는 아마도 더 나은 옵션이 많은 윈도우 프로그래머가하는 것처럼이 두 단계 삭제 및 페인트의 접근 방식은 플리커를 유발하는 경향이 있기 때문에, 전부 WM_ERASEBKGND 메시지 잊어하는 것입니다.WM_ERASEBKGND 메시지에 대한 응답으로 아무것도하지 않는, NULL로 설정 hbrBackground 필드를 남겨하고 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; 
} 
+0

오프 스크린 페인팅에 메모리 DC를 사용하지 않는 한, WM_PAINT의 배경을 지우는 경우에도 깜박임이 생길 수 있습니다. [buffered paint API] (https://msdn.microsoft.com/en-us/library/windows/desktop/bb773257(v=vs.85) .aspx)를 사용하는 것이 좋습니다. – zett42

+0

분명히 모든 깜박 거리는 문제를 해결하는 것은 아니지만 가장 일반적인 경우에 문제를 해결하는 데는 먼 길을 간다. 더 큰 총을 필요로한다면 확실히 사용할 수 있지만 표준 Windows 응용 프로그램을 개발할 때 필요하지는 않습니다. 그리고 누군가가 깜박 거리는 곳의 90 %에서 깨진 그림 코드를 수정하여 모든 것을 무차별하게 버퍼링하지 않는 것이 해결책입니다. –