c++ - 重绘窗口问题

标签 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 struct 进行任何更改。

第一次它很好地绘制了我的 Logo ,第二次(只需调用 InvalidateRect(hWnd,NULL,FALSE); 没有 gGameMain->SendMessage(MESSAGE_ENTER); 这是初始化一些用于绘制的变量。 感谢您阅读本文:)

最佳答案

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

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

其他注意事项:尽量避免在每个 wm_paint 消息上分配一个新的位图。当窗口改变大小时分配位图,并保留它以供多个 wm_paint channel 重用。

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

关于c++ - 重绘窗口问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2821557/

相关文章:

c++ - QList<float*> 类型的 NULL 返回值

c++ - rsa加密/解密polarssl c++

c# - 如何将图像裁剪成圆形?

c# - 使用安全代码将 channel 从一个图像复制到另一个图像

c++ - 为什么 c++11 std::array 使用模板来初始化 max_size 而不是构造函数?

C++/CX ^ 与 &

c# - C# 中的旋转面板

winforms - BufferedGraphicsContext 错误

c++ - 在 C++ 和 Rcpp 中重写慢速 R 函数

c++ - Gdiplus::Bitmap::FromHICON 失败