重绘窗口问题

时间:2010-05-12 18:13:44

标签: c++ gdi+

#include "stdafx.h"

// Mario Headers
#include "GameMain.h"

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst;                                // current instance
TCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name

// Mario global variables =================
CGameMain* gGameMain;
HWND hWnd;
PAINTSTRUCT ps;
// ========================================



// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

// My unprocess function =====================================
void OnCreate(HWND hWnd)
{
}
void OnKeyUp(WPARAM wParam)
{
    switch (wParam) {
                case VK_LEFT:
                    gGameMain->KeyReleased(LEFT);
                    break;
                case VK_UP:
                    gGameMain->KeyReleased(UP);
                    break;
                case VK_RIGHT:
                    gGameMain->KeyReleased(RIGHT);
                    break;
                case VK_DOWN:
                    gGameMain->KeyReleased(DOWN);
                    break;
    }
}
void OnKeyDown(HWND hWnd,WPARAM wParam)
{
    switch (wParam) {
                case VK_LEFT:
                    gGameMain->KeyPressed(LEFT);
                    break;
                case VK_UP:
                    gGameMain->KeyPressed(UP);
                    break;
                case VK_RIGHT:
                    gGameMain->KeyPressed(RIGHT);
                    break;
                case VK_DOWN:
                    gGameMain->KeyPressed(DOWN);
                    break;
            }
}
void OnPaint(HWND hWnd)
{
   HDC hdc = BeginPaint(hWnd,&ps);

   RECT rect;
   GetClientRect(hWnd,&rect);

   HDC hdcDouble        = CreateCompatibleDC(hdc);
   HBITMAP hdcBitmap    = CreateCompatibleBitmap(hdc,rect.right,rect.bottom);
   HBITMAP bmOld        = (HBITMAP)SelectObject(hdcDouble, hdcBitmap);

   gGameMain->SetHDC(&hdcDouble);
   gGameMain->SendMessage(MESSAGE_PAINT);

   BitBlt(hdc,0,0,rect.right,rect.bottom,hdcDouble,0,0,SRCCOPY);
   SelectObject(hdcDouble,bmOld);
   DeleteDC(hdcDouble);
   DeleteObject(hdcBitmap);
   DeleteDC(hdc);
}

void OnDestroy() 
{
    gGameMain->isPlaying = false;
    EndPaint(hWnd,&ps);
}
// My unprocess function =====================================

ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_GDIMARIO));
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_GDIMARIO);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassEx(&wcex);
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{

   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, CW_USEDEFAULT, WIDTH, HEIGHT, 0, NULL, hInstance, NULL);
   if (!hWnd)
   {
      return FALSE;
   }

   // ---------------- Start gdiplus ------------------
   GdiplusStartup(&gdiToken,&gdiStartInput,NULL);
   // -------------------------------------------------

   // Init GameMain
   gGameMain = new CGameMain();

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    switch (message)
    {
    case WM_COMMAND:
        wmId    = LOWORD(wParam);
        wmEvent = HIWORD(wParam);
        // Parse the menu selections:
        switch (wmId)
        {
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;

        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;

        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    case WM_KEYDOWN: 
        OnKeyDown(hWnd,wParam);
        break;
    case WM_KEYUP: 
        OnKeyUp(wParam);    
        break;
    case WM_CREATE:
        OnCreate(hWnd);
        break;
    case WM_PAINT:          
        OnPaint(hWnd);
        break;
    case WM_DESTROY:
        OnDestroy();
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

// Message handler for about box.
INT_PTR CALLBACK About(HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam)

{
    UNREFERENCED_PARAMETER(lParam);
    switch (message)
    {
    case WM_INITDIALOG:
        return (INT_PTR)TRUE;

    case WM_COMMAND:
        if (LOWORD(wParam) == IDOK || LOWORD(wParam) == IDCANCEL)
        {
            EndDialog(hDlg, LOWORD(wParam));
            return (INT_PTR)TRUE;
        }
        break;
    }
    return (INT_PTR)FALSE;
}
int APIENTRY _tWinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,LPTSTR lpCmdLine,int nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.
    MSG msg;
    HACCEL hAccelTable;

    // Initialize global strings
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(hInstance, IDC_GDIMARIO, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_GDIMARIO));

    // Main message loop:
    // GameLoop

    PeekMessage(&msg,NULL,0,0,PM_NOREMOVE);

    while (gGameMain->isPlaying)
    {
        while (PeekMessage(&msg,NULL,0,0,PM_REMOVE)) {
            if (msg.message == WM_QUIT) 
                break;

            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
        if (gGameMain->enterNextState) {
            gGameMain->SendMessage(MESSAGE_ENTER);
            gGameMain->enterNextState = false;
        }

        gGameMain->SendMessage(MESSAGE_UPDATE);
        InvalidateRect(hWnd,NULL,FALSE);
        /*if (gGameMain->exitCurrentState) {
            gGameMain->SendMessage(MESSAGE_EXIT);
            gGameMain->enterNextState = true;
            gGameMain->exitCurrentState = false;
        }*/
        ::Sleep(gGameMain->timer);
            // Do your game stuff here
    }

    GdiplusShutdown(gdiToken); // Shut down gdiplus token

    return (int) msg.wParam;
}

我使用InvalidateRect(hWnd,NULL,FALSE);对于重绘窗口,但我遇到的问题是当我重新绘制而没有任何Game结构的变化。

首先它很好地绘制了我的徽标,第二次(只调用InvalidateRect(hWnd,NULL,FALSE);没有gGameMain-> SendMessage(MESSAGE_ENTER);这是init用于绘制的一​​些变量。 感谢您阅读:)

1 个答案:

答案 0 :(得分:3)

您在每个wm_paint消息中调用BeginPaint(),但是在wm_paint消息处理程序中没有对EndPaint()的相应调用。每个BeginPaint()必须与相应的EndPaint()匹配。在OnDestroy中调用EndPaint()是没用的。

另外,不要删除BeginPaint()返回的DC。它是借来的,不是拥有的。

其他注意事项:尽量避免在每个wm_paint消息上分配新的位图。当窗口改变大小时分配位图,并保持位置以便被多个wm_paint传递重用。

另请注意,您并未优化绘图以仅绘制剪辑矩形中已失效的内容。你正在绘制所有内容,blitting所有内容,并依赖GDI来仅占用实际位于剪辑矩形中的位图的一小部分。随着窗口/位图大小的增加以及屏幕上运行的对象/精灵数量的增加,这将成为性能问题。您应该只绘制可见的内容并在剪辑内。