Программирование на Visual C++. Архив рассылки
Шрифт:
Хорошо, если все сообщения модального диалога проходят через стандартную очередь, почему не вызывается CWnd::OnIdle, как часть этого процесса? Проблема в том, что функция CWnd::RunModalLoop вызывает CWinThread::PumpMessage, однако OnIdle вызывается только внутри CWinThread::Run. MFC вызывает CWinThread::Run для запуска вашего приложения после вызова функции InitInstance. В сокращенном виде функция CWinThread::Run выглядит так:
Я
Обратите внимание, что модальный диалог никогда не будет выполнять этот код, поскольку CWnd::RunModalLoop вызывает CWinThread::PumpMessage сразу из своего собственного цикла обработки сообщений. Он не вызывает CWinThread::Run и, следовательно, никогда не обращается к CWinThread::OnIdle. По-видимому, так было задумано разработчиками. Очевидно, что опасно вызывать OnIdle внутри модального диалога, поскольку многие обработчики сообщений создают временные объекты CWnd, которые, вполне возможно, будут существовать все время, пока существует диалог. Частью процесса обработки OnIdle является освобождение временных карт дескрипторов (handle).
Не могу удержаться от упоминания о том, что механизм временной/постоянной карты дескрипторов (handle map), используемый для связывания дескрипторов HWND с классами CWnd – это один из самых потенциально опасных элементов каркаса приложения, даже более опасный, чем карты сообщений. Проблема "временной карты" непрерывно преследует программистов, особенно в многопотоковых приложениях, делая их трудными для написания в MFC.
Итак, каким же образом обрабатывать период ожидания в приложениях, основанных на диалоге, которые не имеют родительского окна? К счастью, это довольно просто. Разработчики MFC предусмотрели возможность перехвата WM_KICKIDLE. RunModalLoop посылает это частное сообщение MFC (вы не найдете его описания в стандартной документации по Win32 API) все время, пока в очереди диалога нет сообщений, так же как CWinThread::Run вызывает OnIdle. RunModalLoop также поддерживает счетчик и увеличивает его для вас. В результате, WM_KICKIDLE является диалоговым эквивалентом OnIdle. Историческая справка: в ранних версиях MFC была реализована подмена модальных диалогов немодальными в комплексе с WM_KICKIDLE в страницах свойств (property sheets). Видимо, эта схема настоько понравилась, что в дальнейшем все немодальные диалоги стали маскироваться под модальные.
Маленькое замечание: у вас может появиться
Разработчики MFC утверждают, что это опасно, в связи с проблемой пресловутой временной карты. Лучше всего реализовывать обработку интервала ожидания внутри OnKickIdle. Если хотите, то можно объединить общие команды обработки в отдельную функцию, которую и вызывать из CApp::OnIdle и CMyDlg::OnKickIdle.
Раз уж здесь был заведен разговор о предмете обработки интервала ожидания, то не лишним будет упомянуть о следующем – не все программисты знают, что есть также функции OnIdle для классов CDocTemplate и CDocument. Если вы хотите реализовать обработчик периода ожидания для документа или шаблона документа, то все что нужно сделать – это определить одну из этих функций.
Если у вас есть материал (на русском языке) по теме, которая, как вы считаете, будет интересна подписчикам рассылки, не стесняйтесь и присылайте.
Q. У меня программа с использованием MFC и Doc/View. Я вставил RichEditCtrl во вью. (2-ой версии). Установил шрифт с помощью сообщения SetCharFormat. Внимание, вопрос: почему если я ввожу текст с клавиатуры и использую ReplaceText функцию (не сообщение!) фонты различные? Вроде это сообшение не менялось у второй версии. Заранее спасибо за ответ.
A. Думаю, всё дело в режиме IMF_AUTOFONT, который по умолчанию устанавливается для rich edit'а 2-й версии (в 1-й этого режима просто не было). В этом режиме rich edit автоматически переключает язык и фонт, когда пользователь переключает раскладку клавиатуры (в текст rtf вставляется управляющая последовательность "\langXXXX\fX"). Поэтому если язык, установленный в rich edit'е по умолчанию, отличается от выбранного при запуске программы, фонт подменяется как только кто-то начинает набирать текст с клавиатуры, что и приводит к описанному эффекту.
Для решения проблемы следует попробовать отключить режим IMF_AUTOFONT. Выглядит это так (hEdit – дескриптор rich edit'а):
Огромное спасибо Александру за ответ (уже, кстати, третий по счету).
Напоминаю, что в будущем вопросы от Ильи, Александра и всех тех, чьи ответы или материалы были опубликованы, будут рассматриваться вне очереди.
Q. Как просканировать LAN на предмет создания поименного списка машин, чтобы затем можно было изпользовать результат в ListBox'e? Пробовал использовать для этой цели SHBrowseForFolder и связанные ф-ции с установленным флагом CIDL_NETWORK, но открывающееся окно для выбора узла и необходимость "раскрывать плюсики" в локальных группах меня не устраивает. Если можно, в API без MFC.
Сердце Дракона. Том 20. Часть 1
20. Сердце дракона
Фантастика:
фэнтези
боевая фантастика
городское фэнтези
рейтинг книги
Холодный ветер перемен
7. Девяностые
Фантастика:
попаданцы
альтернативная история
рейтинг книги
Последнее желание
1. Ведьмак
Фантастика:
фэнтези
рейтинг книги
Отмороженный 7.0
7. Отмороженный
Фантастика:
рпг
аниме
рейтинг книги
Наследник
1. Рюрикова кровь
Фантастика:
научная фантастика
попаданцы
альтернативная история
рейтинг книги
