简体   繁体   中英

Window created with WINAPI is not drawing objects. What's the problem?

I have my window file ( Window.h ):

LRESULT CALLBACK MessageHandler(HWND, UINT, WPARAM, LPARAM);

class Window
{
private:
    HWND hWnd;
    HINSTANCE hInstance;
    bool running = true;
    const char* ID = "WINAPI_JVM64";
public:
    Window()
    {
        init();
    }

    virtual void draw(Gdiplus::Graphics*) = 0;

    void init()
    {
        hInstance = (HINSTANCE)GetModuleHandle(NULL);
        WNDCLASS wc;

        wc = {};
        wc.style = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc = MessageHandler;
        wc.hInstance = hInstance;
        wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
        wc.hCursor = LoadCursor(NULL, IDC_HAND);
        wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
        wc.lpszClassName = ID;

        assert(RegisterClass(&wc));

        hWnd = CreateWindow(ID, "Title", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                       200, 200, 400, 400, NULL, NULL, hInstance, NULL);

        ShowCursor(true);
        SetForegroundWindow(hWnd);
        SetFocus(hWnd);
    }
    void run()
    {
        MSG msg;
        PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE);
        while(running)
        {
            if(PeekMessage(&msg, hWnd, 0, 0, PM_REMOVE))
            {
                if(msg.message == WM_QUIT)
                    running = false;

                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
            else
            {
                // Here, the draw function is called.
                PAINTSTRUCT ps;
                HDC hdc = BeginPaint(hWnd, &ps);
                Gdiplus::Graphics* g = Gdiplus::Graphics::FromHDC(hdc);
                draw(g);
                EndPaint(hWnd, &ps);
            }
        }
        UnregisterClass(ID, hInstance);
    }
};

And the main file ( main.cpp ):

#include "Window.h"

LRESULT CALLBACK MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch(uMsg)
    {
    case WM_CLOSE:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
    return 0;
}

class AppWindow : public Window
{
public:
    void draw(Gdiplus::Graphics* g) override
    {
        Gdiplus::SolidBrush brown_brush(Gdiplus::Color(255, 128, 57, 0));
        g->FillRectangle(&brown_brush, 0, 0, 200, 200);
    }
};

int main()
{
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);

    AppWindow w;
    w.run();

    Gdiplus::GdiplusShutdown(gdiplusToken);
    return 0;
}

I have the problem that it just won't draw!

It handles every message, everything is good, but it doesn't draw. Even messages of type WM_PAINT are sent, but nothing happens.

Can you spot the problem?

I just want a window class that has an overridable draw() function with a run() function that handles all events, such as WM_LBUTTONDOWN . All of that works fine, the screen just stays blank.

Also, I can't close the window, when pressing the X button in the top-right corner, the window just stays; only after resizing and quickly pressing X , it closes.

As you can see, I have some pretty weird behaviour, and I don't know what the problem is.

Your drawing logic is in the wrong place. It needs to be inside the MessageHandler when processing a WM_PAINT message. PeekMessage() will generate a WM_PAINT message if the window needs to be drawn and no other messages are pending. You can't draw on the window from outside of a WM_PAINT handler.

Also, you are assigning the wrong value to wc.hbrBackground in init() . If you use a color constant like COLOR_WINDOW , you need to add 1 to it. This is stated as much in the WNDCLASS documentation .

Also, in run() , your 1st PeekMessage() to create the message queue is discarding an initial message if one is pending, that message does not get processed by your dispatch loop. That 1st call should be using the PM_NOREMOVE flag instead.

Also, be aware ofthe dangers of filtering window messages in your message loop.

With that said, try this instead:

LRESULT CALLBACK MessageHandler(HWND, UINT, WPARAM, LPARAM);

class Window
{
private:
    HWND hWnd;
    HINSTANCE hInstance;
    const char* ID = "WINAPI_JVM64";

public:
    Window()
    {
        init();
    }

    ~Window()
    {
        cleanup();
    }

    virtual void draw(Gdiplus::Graphics*) = 0;

    void init()
    {
        hInstance = (HINSTANCE)GetModuleHandle(NULL);

        WNDCLASS wc{};
        wc.style = CS_HREDRAW | CS_VREDRAW;
        wc.lpfnWndProc = &MessageHandler;
        wc.hInstance = hInstance;
        wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
        wc.hCursor = LoadCursor(NULL, IDC_HAND);
        wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
        wc.lpszClassName = ID;

        assert(RegisterClass(&wc));

        hWnd = CreateWindow(ID, "Title", WS_OVERLAPPEDWINDOW | WS_VISIBLE,
                       200, 200, 400, 400, NULL, NULL, hInstance, this);
        assert(hWnd != NULL);

        ShowCursor(true);
        SetForegroundWindow(hWnd);
        SetFocus(hWnd);
    }

    void cleanup()
    {
        UnregisterClass(ID, hInstance);
    }

    void run()
    {
        MSG msg;
        PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);

        while (GetMessage(&msg, NULL, 0, 0))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }
};
#include "Window.h"

LRESULT CALLBACK MessageHandler(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    switch (uMsg)
    {
        case WM_NCCREATE:
        {
            Window *pThis = static_cast<Window*>(reinterpret_cast<CREATESTRUCT*>(lParam)->lpCreateParams);
            SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pThis));
            break;
        }

        // DefWindowProc(WM_CLOSE) calls DestroyWindow(),
        // WM_CLOSE is not the right place to call PostQuitMessage()...
        //case WM_CLOSE:
        case WM_DESTROY:
            PostQuitMessage(0);
            break;

        case WM_PAINT:
        {
            Window *pThis = reinterpret_cast<Window*>(GetWindowLongPtr(hWnd, GWLP_USERDATA));
            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, &ps);
            if (pThis)
            {
                Gdiplus::Graphics* g = Gdiplus::Graphics::FromHDC(hdc);
                pThis->draw(g);
                delete g;
            }
            EndPaint(hWnd, &ps);
            return 0;
        }
    }

    return DefWindowProc(hWnd, uMsg, wParam, lParam);
}

class AppWindow : public Window
{
public:
    void draw(Gdiplus::Graphics* g) override
    {
        Gdiplus::SolidBrush brown_brush(Gdiplus::Color(255, 128, 57, 0));
        g->FillRectangle(&brown_brush, 0, 0, 200, 200);
    }
};

int main()
{
    Gdiplus::GdiplusStartupInput gdiplusStartupInput;
    ULONG_PTR gdiplusToken;
    Gdiplus::GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, nullptr);

    AppWindow w;
    w.run();

    Gdiplus::GdiplusShutdown(gdiplusToken);
    return 0;
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM