В прошлом году я указал, что сообщение WM_KILLFOCUS - не подходящее место для проверок корректности ввода. А вот ещё один пример, как игры с фокусом во время обработки WM_KILLFOCUS могут создать хаос.
Рассмотрим edit-контрол, который отображает подсказки всплывающим балуном (balloon tip). Например, элементы для ввода паролей могут предупреждать вас, когда вы пытаетесь набрать пароль с включенным CapsLock. Что вы, вероятно, захотите при этом сделать - так это убирать подсказку, когда пользователь переходит на другой элемент управления, потому что нет смысла предупреждать пользователя о чём-то, что он не использует. Вы можете захотеть реализовать это, изменив обработчик сообщений edit-контрола примерно так:
case Msg of ... WM_KILLFOCUS: if hwndBalloonTip <> 0 then begin DestroyWindow(hwndBalloonTip); hwndBalloonTip := 0; end; ... end; inherited;
Когда вы запустите этот код, он будет работать прекрасно... но только если пользователь не щёлкнет на самой подсказке - тогда каретка edit-а (такая мигающая штучка внутри) исчезнет. Что же произошло?
А произошло то, что вы нарушили процесс смены фокуса ввода уничтожением окна, которому передают фокус! Процесс смены фокуса происходит так:
- Установить фокус ввода в новое окно.
- Отправить сообщение WM_KILLFOCUS в бывшее сфокусированное окно (если есть).
- Отправить сообщение WM_SETFOCUS в новое сфокусированное окно (если есть).
Давайте посмотрим на выполнение кода в этом сценарии.
- Установить фокус ввода в подсказку.
- Отправить сообщение WM_KILLFOCUS в edit-контрол.
- В ответ на WM_KILLFOCUS ваш код уничтожает подсказку.
- Оконный менеджер устанавливает фокус ввода на edit-контрол.
- Нет никого, кому можно было бы послать WM_KILLFOCUS.
- WM_SETFOCUS отправляется edit-у.
- Edit принимает WM_SETFOCUS.
- Edit заканчивает обработку WM_KILLFOCUS (оригинальный обработчик принимает это сообщение).
- Отправляется WM_SETFOCUS подсказке - неудачно (окно подсказки уничтожено).
Посмотрите на поток сообщений, который приходит в оконную процедуру edit-контрола:
- WM_SETFOCUS (от вложенного цикла смены фокуса)
- WM_KILLFOCUS (от исходной смены фокуса)
Есть несколько способов избавиться от этого хаоса.
Во-первых, заметьте, что вам не нужно менять обработку сообщений в edit-е; вы можете реагировать на уведомление EN_KILLFOCUS. Во-вторых, вы можете реагировать на EN_KILLFOCUS отправкой сообщения самому себе, уничтожая подсказку в обработчике этого сообщения. Делая это через промежуточную отправку сообщения, вы избежите рекурсивной смены фокуса, потому что теперь ваш код будет выполняться вне цикла по смене фокуса.
Комментариев нет:
Отправить комментарий
Можно использовать некоторые HTML-теги, например:
<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>
Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку.
Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.
Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.
Примечание. Отправлять комментарии могут только участники этого блога.