首页 > 解决方案 > ExtTextOut 文本不断闪烁,并且在设定的时间后文本恢复为默认字体

问题描述

这是我的第一篇文章,所以请原谅任何错误。

我正在使用 win32 c++,并且我有一个基本窗口,它将给出日期和时间(包括秒),并相应地更新。另外,我已经做到了,所以文本会根据鼠标位置稍微改变位置(几乎就像这个演示一样,https://css-tricks.com/animate-a-container-on-mouse-over-using -透视和变换/但它会根据鼠标位置移动 x 和 y,而不是 z)。然而,每当我运行我的代码时,我的文本都会闪烁,它会瞬间变白,然后再次出现在屏幕上。我认为这是因为我将某些像素绘制了两次,但我不知道如何修复它。此外,经过一定时间(比如 1-2 分钟)后,我的文本字体将恢复为默认字体。在调试过程中,我可以看到进程内存不断增加到 20,然后字体更改为默认值并再次下降。有任何想法吗?我认为在本节的某个地方我搞砸了:

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


switch (message)
{
case WM_COMMAND:
    {
        int wmId = LOWORD(wParam);
        // Parse the menu selections:
        switch (wmId)
        {
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
    }
    break;
  #define SECOND_TIMER 2
case WM_TIMER:
    if (wParam == SECOND_TIMER)
    {
        InvalidateRect(hWnd, NULL, TRUE); // invalidate whole window
    }
    break;
//case WM_ERASEBKGND:
  //  return 1;

case WM_PAINT:
    {
        PAINTSTRUCT ps;
        HDC hdc = BeginPaint(hWnd, &ps);

        POINT point;
        GetCursorPos(&point);
        ScreenToClient(hWnd, &point);
        ClickAnim(point.x, point.y, hdc);

        SetTimer(hWnd, SECOND_TIMER, SECOND_TIMER, NULL);

        HFONT hFont = CreateFont(70, 30, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS,
            CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, VARIABLE_PITCH, TEXT("Segoe UI Light"));
        SelectObject(hdc, hFont);

        TCHAR time[100];
        TCHAR date[100];
        SYSTEMTIME localTime;
        GetLocalTime(&localTime);
        wsprintfW(time, L"%.2u:%.2u:%.2u", localTime.wHour, localTime.wMinute, localTime.wSecond);
        switch (localTime.wMonth)
        {
            case 1:
                wsprintfW(date, L"Jan %.2u, %.2u", localTime.wDay, localTime.wYear);
                break;
            case 2:
                wsprintfW(date, L"Feb %.2u, %.2u", localTime.wDay, localTime.wYear);
                break;
            case 3:
                wsprintfW(date, L"Mar %.2u, %.2u", localTime.wDay, localTime.wYear);
                break;
            case 4:
                wsprintfW(date, L"Apr %.2u, %.2u", localTime.wDay, localTime.wYear);
                break;
            case 5:
                wsprintfW(date, L"May %.2u, %.2u", localTime.wDay, localTime.wYear);
                break;
            case 6:
                wsprintfW(date, L"Jun %.2u, %.2u", localTime.wDay, localTime.wYear);
                break;
            case 7:
                wsprintfW(date, L"Jul %.2u, %.2u", localTime.wDay, localTime.wYear);
                break;
            case 8:
                wsprintfW(date, L"Aug %.2u, %.2u", localTime.wDay, localTime.wYear);
                break;
            case 9:
                wsprintfW(date, L"Sep %.2u, %.2u", localTime.wDay, localTime.wYear);
                break;
            case 10:
                wsprintfW(date, L"Oct %.2u, %.2u", localTime.wDay, localTime.wYear);
                break;
            case 11:
                wsprintfW(date, L"Nov %.2u, %.2u", localTime.wDay, localTime.wYear);
                break;
            case 12:
                wsprintfW(date, L"Dec %.2u, %.2u", localTime.wDay, localTime.wYear);
                break;
        }

        RECT desktop;
        // Get a handle to the desktop window
        const HWND hDesktop = GetDesktopWindow();
        // Get the size of screen to the variable desktop
        GetClientRect(hDesktop, &desktop);
        // TODO: Add any drawing code that uses hdc here...
        //get dimensions of window
        RECT rect;
        GetClientRect(hWnd, &rect);

        HWND desktophWnd = GetDesktopWindow();


        ExtTextOut(hdc, rect.right / 2 - 95 - point.x / 100, rect.bottom / 2 - 40 - point.y / 100, ETO_OPAQUE, NULL, time, _tcslen(time), NULL);

        HFONT smallFont = CreateFont(35, 15, 0, 0, FW_DONTCARE, FALSE, FALSE, FALSE, DEFAULT_CHARSET, OUT_OUTLINE_PRECIS,
            CLIP_DEFAULT_PRECIS, ANTIALIASED_QUALITY, VARIABLE_PITCH, TEXT("Segoe UI"));
        SelectObject(hdc, smallFont);
        ExtTextOut(hdc, rect.right / 2 - 85 - point.x / 100, rect.bottom / 2 - 70 - point.y / 100, ETO_OPAQUE, NULL, date, _tcslen(date), NULL);



        EndPaint(hWnd, &ps);

    }
    break;
case WM_DESTROY:
    PostQuitMessage(0);
    break;
default:
    return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;

}

标签: c++winapi

解决方案


您在绘制期间调用CreateFont了几次,但您永远不会从设备上下文中取消选择该字体,也不会删除字体对象。由于字体总是相同的,只需创建一次并重用该对象。这将减少一些油漆时间。

至于闪烁,第三个参数InvalidateRect应该是FALSE(这样BeginPaint调用时背景不会被抹掉)。当您开始绘制窗口时,请擦除您将要填充的窗口部分(可能包括时间的先前位置)。在打电话之前也要做尽可能多的工作BeginPaint。这将减少闪烁,但可能无法完全消除它。要完全消除它需要某种双缓冲。


推荐阅读