0

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;
}
4

2 回答 2

2

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().

于 2013-07-16T13:39:28.843 回答
2

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.

于 2013-07-16T13:40:15.237 回答