· окно изменяет размер. Обычно это приводит к появлению неверных прямоугольников только при увеличении размера окна и только на дополнительно появившейся поверхности. Однако, если при регистрации класса окна Вы указали стиль CS_HREDRAW или CS_VREDRAW, то все окно целиком будет рассматриваться как неверное.
· Вами вызвана одна из функций:
·
void InvalidateRect( hWnd, lpRect, fErase );
void InvalidateRgn( hWnd, hRgn, fErase );
Параметры этих функций: hWnd — хендл окна, содержащего прямоугольник (или регион), нуждающийся в перерисовке. lpRect — указатель на структуру типа RECT, описывающую прямоугольник, или hRgn — хендл нужного региона. fErase — логическая (TRUE,FALSE) величина, указывающая, нужно ли восстанавливать фон неверной области, или нет.
Неверный прямоугольник не появляется при перемещении курсора мыши или пиктограмм через область окна — Windows самостоятельно сохраняет и восстанавливает окно под курсором (или пиктограммой).
В некоторых случаях неверные прямоугольники могут создаваться, а могут и не создаваться. Это может быть, если часть окна становиться видимой после использования диалогов, выпадающих меню или после вызова функции MessageBox, являющейся частным случаем стандартного диалога. В этих случаях Windows может сохранять текст под появляющимся окном и восстанавливать его позже. Однако это делается не всегда и зависит от разных факторов — размера диалога или меню, режима его создания и других факторов.
Допустим, что в результате какого–либо события появился неверный прямоугольник. Что с ним происходит дальше?
Windows, обнаружив неверный прямоугольник, принадлежащий какому–либо окну, ставит в очередь приложения сообщение WM_PAINT, адресованное этому окну. Оконная процедура, получив это сообщение, перерисовывает требуемую часть окна (или большую), после чего сообщает Windows о том, что неверный прямоугольник исправлен.
Если этого не сообщить Windows, то будет считаться, что прямоугольник остался неверным, и снова будут генерироваться сообщения WM_PAINT этому окну. Поэтому очень важно не оставлять после WM_PAINT неверных прямоугольников.
Таким образом осуществляется поддержание окна в требуемом состоянии. Однако перерисовка является медленным процессом (к тому же многие приложения перерисовывают большую часть окна, чем надо), а неверные прямоугольники могут появляться в нескольких экземплярах, иногда перекрывающихся, до того, как приложение начнет обрабатывать WM_PAINT.
Поэтому в Windows сообщение WM_PAINT трактуется не как сообщение, а скорее как состояние: если в очереди приложения есть сообщение WM_PAINT, то окно надо перерисовать. А если в это время появляются новые неверные прямоугольники, то новых сообщений WM_PAINT в очередь не попадает, а просто новый неверный прямоугольник объединяется со старым. Обычно в результате объединения возникает некоторая неверная область сложной формы[12].
Сообщение WM_PAINT является низкоприоритетным. Чем отличается низкоприоритетное сообщение от нормального? Тем, что, если в очереди приложения есть только сообщения с низким приоритетом, то Windows может передать управление другому приложению, имеющему в очереди сообщения нормального приоритета (в Windows только два сообщения являются низкоприоритетными: WM_PAINT и WM_TIMER).
Эти две особенности позволяют Windows сравнительно легко переносить продолжительное рисование окна, хотя при этом перерисовываемая поверхность зачастую приближается к размерам всего экрана. Специфичная обработка сообщения WM_PAINT является причиной того, что в Windows рекомендуется сосредоточивать все операции по выводу в окно в обработчике сообщения WM_PAINT.
Если Вам надо самим осуществить какой–либо вывод в окно (понятно, что такая необходимость возникает и при обработке других сообщений), то настоятельно рекомендуется следующий метод:
· все операции по выводу сосредотачиваются в обработчике сообщения WM_PAINT.
· когда у Вас возникает необходимость осуществить вывод в окно, Вы вызываете функцию InvalidateRect, которая маркирует нужную часть окна как неверную, и, следовательно, в очередь приложения попадает сообщение WM_PAINT.
· при этом сообщение только лишь оказывается в очереди, но оно не попадает на обработку немедленно, реальный вывод произойдет несколько позже. Если Вам надо именно сейчас осуществить вывод в окно, то добавьте вызов функции UpdateWindow. Эта функция немедленно передаст оконной процедуре сообщение WM_PAINT для его обработки.
Конечно, осуществление вывода при обработке других сообщений не является ошибкой, хотя делать этого не стоит, особенно если рисование сколько–нибудь сложное. К сожалению, всегда следовать этому правилу почти невозможно, однако нужны веские причины для его нарушения.
При обработке сообщения WM_PAINT стоит придерживаться нескольких правил, специфичных для этого сообщения:
Первое: Никогда не передавайте сообщение WM_PAINT непосредственно окну. Для этого существует функция UpdateWindow, которая генерирует это сообщение, если неверный прямоугольник существует.
Второе: Рекомендуется начинать обработку сообщения WM_PAINT с функции:
HDC BeginPaint( hWnd, lpPaintstruct );
и заканчивать функцией
void EndPaint( hWnd, lpPaintstruct );
где lpPaintstruct — указатель на структуру типа PAINTSTRUCT. Эти функции выполняют несколько нужных дополнительных действий для обработки сообщения WM_PAINT, в том числе объявляют внутреннюю область окна корректной.
Наконец: Если все же Вы не используете BeginPaint...EndPaint, то обязательно объявляйте перерисованную область верной с помощью функции ValidateRect или ValidateRgn.
void ValidateRect( hWnd, lpRect );
void ValidateRgn( hWnd, hRgn );
Параметры этих функций: hWnd — хендл окна, содержащего прямоугольник (или регион), нуждающийся в перерисовке. lpRect — указатель на структуру типа RECT, описывающую прямоугольник, или hRgn — хендл нужного региона.
Рассматривая сообщение WM_PAINT и неверные прямоугольники мы обсудили основные правила осуществления вывода в Windows. Теперь обзорно познакомимся с правилами осуществления вывода графической информации в окно.
В первом же написанном приложении 1a.cpp мы увидели, что функция вывода текста TextOut использовала не хендл окна, а так называемый хендл контекста устройства (HDC,devicecontext). Зачем он понадобился? и почему бы не использовать вместо него хендл окна?
Дело в том, что все средства вывода в Windows относятся не к менеджеру окон, а к графическому интерфейсу устройств (GDI). GDI представляет собой библиотеку функций для выполнения графического вывода на различных устройствах, не только на дисплее. При создании GDI стремились сделать работу с устройствами независимой от самих устройств. Так, одни и те же функции, осуществляющие вывод текста, рисование линий и т.д. могут применяться для работы с дисплеем, принтером, плоттером и другими устройствами.
Для этого пришлось ввести дополнительное понятие — контекст устройства, идентифицируемый его хендлом. Все функции вывода взаимодействуют с этим контекстом. Часто даже говорят, что функции GDI рисуют на контексте, а не непосредственно на устройстве. Контекст устройства описывает так называемые атрибуты контекста и непосредственно характеристики устройства, на котором осуществляется вывод.
Атрибуты контекста устройства независимы от самого устройства. Они характеризуют то изображение, которое будет рисоваться. В число атрибутов входят кисти, перья, цвет текста, цвет фона и многое другое. Так, назначив контексту устройства текущее перо вы определяете толщину, цвет и стиль (сплошная или прерывистая) тех линий, которые будут отображаться последующими вызовами функций, рисующих эти линии. При необходимости нарисовать линию другого стиля вы должны поменять текущее перо. Аналогично определяются кисть, используемая для закраски фона фигур, шрифт, применяемый при выводе текста, и много других атрибутов контекста устройства.
Информация об устройстве описывает непосредственно возможности самого графического устройства. Функции GDI взаимодействуют с устройством опосредованно — через контекст и через драйвер этого устройства. Благодаря наличию информации об устройстве одна и та же функция GDI способна осуществлять вывод на любое устройство, для которого существует необходимый драйвер. Так, вы можете выбирать перо или кисть любого цвета, а GDI примет меры, что бы необходимое изображение было получено как на цветном дисплее, так и на черно–белом принтере или плоттере.
Как правило вы можете не заботиться о характеристиках устройств, на которых реально будет работать приложение. Однако, при разработке сложных приложений, которые могут широко распространяться, вы должны все–таки позаботиться о некоторых вопросах совместимости — например, при назначении цветов стоит их подбирать так, что бы при переходе на черно–белое оборудование изображение осталось бы различимым. Часто лучшим решением является возможность легкой настройки программы пользователем под его конкретную аппаратуру.
Обычно надо предусматривать следующие варианты:
· если приложение осуществляет вывод только в окно, то надо учитывать возможность работы:
· с разным разрешением — от 640x400, 640x480 и до часто встречающихся 1024x768, 1280x1024. Следует подчеркнуть, что в некоторых случаях возможны режимы работы монитора только с 400 строками развертки, а не с 480, как считают обычно. Было бы очень желательно, что бы даже в таком режиме все диалоги и окна умещались на экране.
· с разным числом цветов — от 8 и до более чем 16 миллионов цветов (16 777 216). Чисто монохроматические дисплеи (черный и белый) уже практически не встречаются, а вот дисплеи дешевых переносных компьютеров часто дают только 8–16 градаций серого; причем различимость цветов может быть невелика.
· с разными настройками системной палитры; включая контрастные и энергосберегающие режимы (иногда применяются для переносных компьютеров).