Question

I used DrawText function within WM_TIMER, but it dont work. How to fix this? Thank you!

LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
{
    PAINTSTRUCT ps;
    HDC hdc;
    switch (message)
    {
    case WM_CREATE:
        SetTimer(hwnd,23, 1000,NULL);
        break;

    //case WM_TIMER: ***** dont work *****
    case WM_PAINT: // ***** work, but used 25% CPU *****
        {
        RECT rect;
        HFONT hFont;
        hdc = BeginPaint(hwnd, &ps);
        hFont = CreateFontA(16,0,0,0,FW_NORMAL,FALSE,FALSE,FALSE,DEFAULT_CHARSET,OUT_OUTLINE_PRECIS, CLIP_DEFAULT_PRECIS,ANTIALIASED_QUALITY, VARIABLE_PITCH,TEXT("Arial"));
        SelectObject(hdc,hFont);
        SetRect(&rect, 3, 3, 90, 50);
        SetTextColor(hdc, RGB(0,0,255));

        time_t rawtime;
        struct tm * timeinfo;
        char buffer [80];

        time ( &rawtime );
        timeinfo = localtime ( &rawtime );
        strftime (buffer,80,"%I:%M:%S %p\n%m/%d/%Y",timeinfo);

        wchar_t wtext[30];
        mbstowcs(wtext, buffer, strlen(buffer)+1);//Plus null
        LPWSTR ptr = wtext;



        DrawTextW(hdc, ptr, -1,&rect, DT_NOCLIP | DT_CENTER);

        DeleteObject(hFont);

        InvalidateRect(hwnd, &rect, TRUE);
        UpdateWindow(hwnd);

        EndPaint(hwnd, &ps);
        break;
        }
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hwnd, message, wparam, lparam);
    }
    return 0;
}
Was it helpful?

Solution

Do not call InvalidateRect() or UpdateWindow() from WM_PAINT, or you will create an infinite loop of repaints.

Do not paint from the WM_TIMER. It can be done (with GetWindowDC() instead of BeginPaint() but it isn't such a good idea.

Instead put the InvalidateRect() in the WM_TIMER and leave the drawing code in WM_PAINT. You can optimize, as @typ1232 said in the comments, by creating the font only once, but that's not strictly necessary.

The UpdateWindow() call should not generally be necessary, unless you are in a tight CPU loop and need to show the window just now: if the invalidation is done in a timer and the timeout is not too short you won't need it. But if your timeout is very short you can force the redraw calling UpdateWindow() just after InvalidateRect().

OTHER TIPS

Your WM_TIMER code should prepare the string to be drawn, save it and then call InvalidateRect. The WM_TIMER code can not draw directly, and one reason is that BeginPaint will not work properly during a WM_TIMER message. BeginPaint is only defined during a WM_PAINT message. So WM_TIMER can prepare the data to be drawn, but then use InvalidateRect to request that a WM_PAINT be generated.

You must also remove the InvalidateRect and UpdateWindow calls from the WM_PAINT code. They will cause an infinite loop of painting.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top