Функция вывода текста с переменной, которая не обновляется

#c #winapi

#c #winapi

Вопрос:

Я создаю настольное приложение в VS 2019 и пытаюсь распечатать переменную x с TextOut помощью . Я знаю, что проблема не в том, как я изменяю переменную x, потому что она выводит ее правильно OutputDebugString . Что я делаю не так TextOut ?

Вот соответствующая часть моего кода:

 case WM_PAINT:
    {
        float x = 1;
        while (x < 100) {
            x = x   0.01;

            PAINTSTRUCT ps;
            HDC hdc = BeginPaint(hWnd, amp;ps);
            std::string s = std::to_string(x);
            std::wstring stemp = s2ws(s);
            LPCWSTR sw = stemp.c_str();
            OutputDebugString(sw);
            TextOut(hdc, x * 100, 150, sw, 3);
            EndPaint(hWnd, amp;ps);
        }
    }
 

Я ожидаю, что медленно увеличивающиеся числа (1.01, 1.02, 1.03 и т.д.) остановятся на 100, но вместо этого я получаю застой 1.0 в окне. Любая помощь будет с благодарностью принята.

Комментарии:

1. Насколько я помню, WM_PAINT перерисовывает только ту часть окна, которую необходимо перерисовать (например, была закрыта другим окном). Возможно, в этом проблема.

2. Использование плавающей точки для координат является хитроумным. Лучше выполнять координаты в целочисленной арифметике, а затем делить на 100 при генерации строки. Кроме того, вы никогда не сможете увидеть 0.01, потому что x начинается с 1.0.

3. Возможно, вы захотите проверить, что строка, которую вы выводите, на самом деле имеет длину не менее 3 символов. Я полагаю std::to_wstring , это может гарантировать значение с плавающей запятой, по крайней мере, в языковом стандарте «C», но я не знаю, верно ли это для всех языков.

Ответ №1:

Вам нужно звонить (Begin|End)Paint() только один раз за WM_PAINT каждое сообщение. Это происходит потому BeginPaint() , что область чертежа обрезается, чтобы включить только те области, которые были признаны недействительными, а затем проверяет окно. Таким образом, в вашем примере 2-й и последующим итерациям цикла негде будет рисовать, так как область отсечения будет пустой.

Вам нужно переместить вызовы за (Begin|End)Paint() пределы вашего цикла.

Также нет необходимости вручную преобразовывать ваши std::string данные в std::wstring , просто используйте версии ANSI OutputDebugString() и TextOut() и позвольте им конвертировать в Unicode внутренне для вас.

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

    float x = 1;
    while (x < 100) {
        x = x   0.01;
        std::string s = std::to_string(x);
        OutputDebugStringA(s.c_str());
        TextOutA(hdc, x * 100, 150, s.c_str(), 3);
    }

    EndPaint(hWnd, amp;ps);
    break;
}
 

Если вы действительно хотите использовать std::wstring , просто используйте std::to_wstring() вместо std::to_string() :

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

    float x = 1;
    while (x < 100) {
        x = x   0.01;
        std::wstring s = std::to_wstring(x);
        OutputDebugStringW(s.c_str());
        TextOutW(hdc, x * 100, 150, s.c_str(), 3);
    }

    EndPaint(hWnd, amp;ps);
    break;
}
 

Комментарии:

1. BeginPaint Функция автоматически проверяет всю клиентскую область (нет EndPaint ). Также стоит упомянуть: занятый (повторный) цикл рисования внутри WM_PAINT обработчика проблематичен. Это может привести или не привести к желаемому результату и, безусловно, приведет к тому, что приложение перестанет отвечать как на ОС, так и на пользователя.