创建窗口后未调用WM_PAINT

时间:2010-10-17 19:32:47

标签: c++ winapi

我一直在使用Windows api for uni,但是在创建初始化之后我无法获得窗口消息来调用WM_PAINT。它在创建窗口时调用它,但不在之后调用。

所有其他消息被调用!只是无法调用WM_PAINT。

这是我们必须使用Windows api制作的游戏库的一部分(目标是学习windows api的升级,而不是制作游戏库的复杂性)。

从我收集的UpdateWindow(句柄)命令调用启动WM_PAINT消息,但无论我在哪里放置此命令(当前在游戏循环中)我都无法调用该消息。

有很多代码,所以我稍微修剪了一下。

我知道我有多个WM_PAINT案例,它们是试图确保其通过的结果。

窗口创建         HWND hwnd;

    hwnd = CreateWindowEx(WS_EX_APPWINDOW | WS_EX_WINDOWEDGE,
        L"FirstWindowClass",
        L"Mootlib",
        WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX,
        CW_USEDEFAULT,
        CW_USEDEFAULT,
        m_screenWidth,
        m_screenHeight,
        NULL,
        NULL,
        WindowsUtilities::windowInstance(),
        NULL);

注册窗口

    WNDCLASSEX  wcex;                                   

    wcex.cbSize        = sizeof (wcex);             
    wcex.style         = CS_HREDRAW | CS_VREDRAW;       
    wcex.lpfnWndProc   = windowProc;
    wcex.cbClsExtra    = 0;                             
    wcex.cbWndExtra    = 0;                             
    wcex.hInstance     = WindowsUtilities::windowInstance();
    wcex.hIcon         = 0; 
    wcex.hCursor       = LoadCursor (NULL, IDC_ARROW);  

    wcex.hbrBackground = (HBRUSH) (COLOR_WINDOW+1);
    wcex.lpszMenuName  = NULL;                          
    wcex.lpszClassName = L"FirstWindowClass";               
    wcex.hIconSm       = 0; 

    RegisterClassEx (&wcex);

Winproc传

    LRESULT CALLBACK windowProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
    {
        LONG_PTR lptr = GetWindowLongPtr(hwnd, GWLP_USERDATA);

        switch(message)
        {
        case(WM_PAINT):
            int f = 3;
        }

        if (lptr)
        {
            Window* obj = reinterpret_cast<Window*>(lptr);
            return obj->handleWindowsMessages(message, wParam, lParam);
        }
        else
            return DefWindowProc(hwnd, message, wParam, lParam);
    }

内部命令

LRESULT Window::handleWindowsMessages(UINT message, WPARAM wParam, LPARAM lParam)
{

    std::wstring szHello = L"Hello, world!";
    PAINTSTRUCT ps;
    HDC hdc;

    switch(message)
    {
    case(WM_PAINT):
        hdc = BeginPaint(m_handle, &ps); 
        TextOut(hdc, 0, 0, L"Hello, Windows!", 15); 
        EndPaint(m_handle, &ps); 
        return 0; 

    case(WM_CLOSE):
        quitGame();
        return 0;

    // Move Me!!!
    case(WM_KEYDOWN):
    case(WM_LBUTTONDOWN):
    case(WM_RBUTTONDOWN):
        inputManager().addButtonEvent(reinterpret_cast<int&>(wParam), BUTTON_DOWN);
        return 0;

    // Move Me!!!
    case(WM_KEYUP):
    case(WM_LBUTTONUP):
    case(WM_RBUTTONUP):
        inputManager().addButtonEvent(reinterpret_cast<int&>(wParam), BUTTON_UP);
        return 0;   
    }

    return DefWindowProc(handle(), message, wParam, lParam);
}

游戏循环

        while(IsWindowVisible(handle()))
        {
            UpdateWindow(handle());
            WindowsUtilities::processMessages();

            draw();
            update();

            inputManager().update();
            inputManager().clearButtonUpEvents(); // this should be in the input update()
        }

感谢。

4 个答案:

答案 0 :(得分:2)

首先,我真的不喜欢你的游戏循环,因为它根本不是Windows消息泵的显而易见的地方。

您需要拨打PeekMessage()GetMessage()TranslateMessage()&amp;检索到的任何邮件都DispatchMessage()。许多不熟悉Windows的人会过滤消息,无论是在一个范围内还是在窗口中:不要 - 总是为当前线程上的所有窗口抽取所有消息。

然后,您需要调用InvalidateRect来标记要重新绘制的窗口区域。游戏将要传递FALSE,因为在WM_PAINT中绘制整个场景时,绘制背景只是浪费时间。

RedrawWindow对于游戏非常有用,如果您只想将窗口的整个部分标记为脏并在一个步骤中重绘它。 InvalidateRect的优点是它只是将矩形添加到脏区域,所以如果你的游戏只包含几个小的“活动”精灵,每个精灵动画都可以标记相应的矩形脏和窗口收到脏帐户并在下次调用UpdateWindow时批量绘制它们,或让消息循环生成WM_PAINT消息。

答案 1 :(得分:1)

以下是规范Windows代码的片段,在Visual Studio中创建新的Win32项目时会自动生成:

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

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

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

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

   return TRUE;
}

注意你的遗失:你忘了打电话给ShowWindow()。

答案 2 :(得分:0)

如果您希望调用WM_PAINT,可以使用RedrawWindowInvalidateRect

答案 3 :(得分:-1)

MSDN声明:

  

UpdateWindow函数更新了   指定窗口的客户区域   发送WM_PAINT消息给   窗口如果窗口的更新区域   不是空的

您的问题是您尚未设置更新区域。

你可以这样做:

SendMessage( handle(), WM_PAINT, 0, 0 );