#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
обработчика проблематичен. Это может привести или не привести к желаемому результату и, безусловно, приведет к тому, что приложение перестанет отвечать как на ОС, так и на пользователя.