iRomul
iRomul

Reputation: 351

WinAPI timer don't send WM_TIMER event

I'm workin at very simple program that animate shape movement. Animation can be switched to on/off mode using right mouse button. I'm creating timer in window procedure and waiting for WM_TIMER event. But after creating timer (return value of SetTimer is 1) WM_TIMER case never reaching (i'm set break point at next line to detect it). My window procedure:

fn CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) -> LRESULT {

    PAINTSTRUCT ps;
    RECT win;
    GetClientRect(hWnd, &win);
    int w = win.right - win.left;
    int h = win.bottom - win.top;

    static COLORREF shape_color = RGB(0, 255, 255);

    static int x = 50, y = 50;
    static int r = 40;

    int step = 50;
    static bool animation = false;

    switch (message) {

    case WM_LBUTTONDOWN:

        GetColorDlg(hWnd, shape_color);
        break;

    case WM_RBUTTONDOWN:

        animation = !animation;
        if (animation) {
            timer_id = SetTimer(hWnd, 1, 500, NULL);
        }
        else {
            KillTimer(hWnd, timer_id);
        }
        break;

    case WM_TIMER:
        ++x_offset;
        y_offset = sin(x_offset) * 20;

    case WM_KEYDOWN: {

        if (!animation) {
            switch (wParam) {
            case VK_UP:
                y -= step;
                break;
            case VK_DOWN:
                y += step;
                break;
            case VK_LEFT:
                x -= step;
                break;
            case VK_RIGHT:
                x += step;
                break;
            }
        }

        y += y_offset;
        x += x_offset;

        x = x + r > w ? w - r : x - r < 0 ? r : x;
        y = y + r > h ? h - r : y - r < 0 ? r : y;

        RECT invalid_area;
        invalid_area.top = y + r;
        invalid_area.left = x - r;
        invalid_area.bottom = y - r;
        invalid_area.right = x + r;
        InvalidateRect(hWnd, &invalid_area, true);
        break;

    }

    case WM_SIZE: {

        if (x + r > w)
            x = w - r;

        if (y + r > h)
            y = h - r;

        break;

    }

    case WM_PAINT: {

        //HDC hdc = BeginPaint(hWnd, &ps);
        HDC hdc = GetDC(hWnd);

        HBRUSH shape_brush = CreateSolidBrush(shape_color);
        HPEN   shape_pen = CreatePen(PS_SOLID, 2, RGB(0, 0, 0));

        SelectObject(hdc, shape_pen);
        SelectObject(hdc, shape_brush);

        Circle(hdc, x, y, r);

        DeleteObject(shape_pen);
        DeleteObject(shape_brush);
        DeleteObject(hdc);
        ReleaseDC(hWnd, hdc);
        //EndPaint(hWnd, &ps);
        break;

    }

    case WM_DESTROY:
        PostQuitMessage(0);
        break;

    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;

}

Upvotes: 0

Views: 405

Answers (1)

Jonathan Potter
Jonathan Potter

Reputation: 37122

In your WM_PAINT handler you're not calling BeginPaint / EndPaint, which means your window will always remain marked as invalid. This will generate a continuous stream of WM_PAINT messages, and this stops your timer from working because WM_TIMER messages are only generated when the message queue is empty.

See If my WM_TIMER handler takes longer than the timer period, will my queue fill up with WM_TIMER messages? for the basic algorithm that controls when WM_TIMER messages are generated.

Upvotes: 4

Related Questions