понедельник, 27 декабря 2010 г.

Как предполагалось использовать LockWindowUpdate?

Это перевод How is LockWindowUpdate meant to be used? Автор: Реймонд Чен.

Теперь когда мы знаем, как работает LockWindowUpdate, мы можем посмотреть, для чего она предназначена.

Вообще-то предлполагаемая цель LockWindowUpdate может быть выражена всего одним словом: перетаскивание. Но про это позже.

Цель LockWindowUpdate заключается в том, что она позволяет программе временно захватить ответственность за рисование окна. Конечно же, чтобы это сделать, вам нужно запретить оконной процедуре (или кому-то ещё) делать их обычные операции по рисованию; в противном случае два куска кода (код, который обычно рисует, и код, который пытается захватить контроль) будут сражаться за контроль за окном, и вы получите ужасную ситуацию, когда никто не знает, что происходит.

Но если вы заблокируете окно, то как же вы сможете рисовать на нём? Для этого вы используете флаг DCX_LOCKWINDOWUPDATE в функции GetDCEx. Этот флаг означает: "Дай мне нарисовать на окне, даже хотя оно заблокировано для обновления". Конечно же, этот флаг должен указывать только код, который заблокировал окно - иначе это создаст конфликт, которого LockWindowUpdate и пыталась избежать изначально.

Поскольку люди так любят таблицы, то я сделал одну, которая подводит итоги, что меняется, когда окно блокируется для обновления:

Обычное поведение Окно заблокировано для обновления
BeginPaint, GetDC и т.д.. Операции рисования рисуют на окне Операции рисования ничего не рисуют, но задетая область запоминается для обновления в будущем
GetDCEx с флагом DCX_LOCKWINDOWUPDATE (не используется) Операции рисования рисуют на окне

Другими словами, когда окно блокируется для обновления, способность рисования на окне забирается у обычных функций по работе с DC (BeginPaint и друзья) и отдаётся GetDCEx(DCX_LOCKWINDOWUPDATE). Заметьте, что если заблокированного окна нет, то вы не должны использовать флаг DCX_LOCKWINDOWUPDATE; цель флага - сказать "Я - тот самый, кто вызвал LockWindowUpdate. Пропусти меня!"

Это вроде как эквивалент старой комедии, где вы говорите охраннику: "В комнату никого не пускать". А потом вы возвращаетесь, но охранник не впускает вас в комнату.

"Извините, сэр, но мне нельзя пускать никого в комнату."

"Но это же я сказал тебе не пускать никого."

"Так точно, сэр. Именно это я и делаю. Не пускаю никого в комнату."

Ошибка заключалась в первом приказе охраннику. Нужно было сказать: "Никого, кроме меня". И DCX_LOCKWINDOWUPDATE - это то, с помощью чего вы говорите менеджеру окон: "Это я и есть. Впусти меня".

Если вы вернётесь назад и посмотрите, как работает LockWindowUpdate, то вы увидите, что если окно, которое было заблокировано, не пытается рисовать, то когда окно разблокируется, но ничего не обновляется. В то время как стиль класса CS_SAVEBITS автоматически сохраняет и восстанавливает оригинальные пиксели, когда окно удаляется с экрана, LockWindowUpdate ничего такого не делает. Это ваша ответственность восстановить любые пиксели окна, которые вы меняли пока окно было заблокировано для изменения. Обычно это делается сохранением исходных пикселей во внеэкранный растр до выполнения рисования и восстановления их назад перед разблокировкой окна.

OK, вот предполагаемый шаблон использования:
  • Когда вы хотите взять контроль над рисованием другого окна, вы вызываете LockWindowUpdate для этого окна.
  • Вы сохраняете пиксели окна, на котором вы собираетесь рисовать.
  • Вы рисуете свои пиксели. (Эти пиксели часто являются модификацией исходных пикселей. К примеру, вы можете добавить изображение объекта, который перетаскивается поверх окна.)
  • Повторяете эти действия, пока длится ваша операция.
  • Когда операция завершается, вы восстанавливаете исходные пиксели и вызываете LockWindowUpdate(0).
В следующий раз, мы более пристально посмотрим на это слово "перетаскивание" и то, как оно тесно связано с концепцией LockWindowUpdate.

Даже хотя мы только начали говорить о LockWindowUpdate, вы должны уже знать ответ на этот вопрос.

(Примечание: цель этой серии - описать способ, которым должна была использоваться LockWindowUpdate, а не был ли это удачный дизайн или нет.)

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

Отправить комментарий

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.