Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате |
Форум программистов > Visual C++/MFC/WTL > Сообщение полного конца |
Автор: Rickert 29.5.2008, 08:56 |
Есть окно, на нём куча элементов, все там по своему инициализируются и всё такое. Как мне поймать момент конца полной инициализации всех элементов, то бишь момент, после которого окно перейдёт в режим ожидания сообщений: когда уже всё отрисованно? |
Автор: deniska 29.5.2008, 10:02 |
может OnIdle переопределить? вроде как вызывается когда очередь сообщений пуста |
Автор: Rickert 29.5.2008, 10:44 |
Пардон, не сказал: у меня модальный диалог, для него OnIdle не перегрузишь насколько мне известно. |
Автор: Rickert 29.5.2008, 11:46 |
OnEnterIdle тоже ни при делах. |
Автор: deniska 29.5.2008, 12:14 |
объект CWinApp есть в каждом приложении... как модальность\немодальность окна может влиять? ты ведь не для диалога перегружаешь а для основного потока своего приложения. как только освобождается очередь сообщений для него, по идее сразу должен попасть в свой обработчик OnIdle |
Автор: Rickert 30.5.2008, 07:30 |
deniska, в одной из тем, здесь же на форуме я задавал вопрос немного другого плана и там, как мне было объяснено: OnIdle не вызывается, потом что модальный диалог идёт не через InitInstance(). Плюс к этому я уже трижды пробовал перегружать OnIdle в потомке от CWinApp - результата нет. |
Автор: Andrey44 30.5.2008, 07:47 | ||
Может поможет
|
Автор: deniska 30.5.2008, 08:22 |
Rickert, по ходу ты прав. сейчас попробовал - не заходит. тогда можно в какойнить таймер воткнуть функцию, которую Andrey44 дал... а вообще если вся инициализация контролов находится в OnInitDialog, то наверно следующий после этой функции вызов OnPaint последний. по крайней мере можно с GetMessage по экспериментировать, проверить. |
Автор: Earnest 30.5.2008, 11:36 |
Модальному диалогу должно прийти WM_KICKIDLE - первый раз оно приходит после окончания инициализации, а дальше - как OnIdle. Это private MFC сообщение, определено в afxpriv.h |
Автор: Earnest 2.6.2008, 15:38 |
WM_KICKIDLE не помещается в очередь, а посылается прямо. Ставь обработчик - поймаешь. |
Автор: Rickert 3.6.2008, 03:59 | ||
Так как я его поставлю? В BEGIN_MESSAGE_MAP()? Нету там ON_WM_KICKIDLE. MSDN тоже, кстати, мало что внятного может сказать про WM_KICKIDLE. Где ты про него вычитала интересно? ![]() |
Автор: dizzy1984 3.6.2008, 08:22 | ||||||
Подобное можно узнать кропотливой отладкой исходников MFC. Интересующее нас место тут (файл wincore.cpp, урезаны незначимые места)
Видно, что в код, расположенный в первой фазе бесконечного цикла, будет выполнен на следующей итерации после того, как очередь сообщений опустеет. Выход из него осуществляется в зависимости от результата ответа на магическое сообщение "SendMessage(WM_KICKIDLE, MSGF_DIALOGBOX, lIdleCount++)". Ясно, что если это FALSE - бесконечные цикл войдет во вторую фазу и на этом успокоится. Соответственно Earnest уже сказала, что SendMessage(WM_KICKIDLE...) займется тем, что вызовет процедуру окна, которую MFC зарегистрировала как "AfxWndProc"(тот же Wincore.cpp) и которая в конечном счете найдет CWnd, соответсвующее полученному ей HWND и просмотрит его карту отклика. Там она может увидеть обработчик сообщения WM_KICKIDLE. В таком случае вместо стандартного обработчика DefWindowProc будет взят именно он. Резюмируя, пишем код
Замечательно, работает, но зачем мы все это написали? Я не знаю. Все это ни к чему, т.к идеологически неверно - такой обработчик будет вызываться постоянно, после появления новых сообщений в очереди. Нормальный вариант решения проблемы с моей точки зрения будет посылка произвольного сообщения из OnInitDialog. Обработчик такого сообщения будет вызван после того, как очередь опустеет. Пишем код
|
Автор: Earnest 3.6.2008, 10:27 | ||
Убойный аргумент, что и говорить. Насчет WM_KICKIDLE... я его использую для аснхронного обновления контролов диалога, очень полезная вешь (примерно так, как работает WM_IDLEUPDATECMDUI в фрейворке... Насчет "приходить много раз" - да, конечно, однако нетрудно поставить какой-то флаг инициализации. Но это дело вкуса - я лично терпеть не могу юзеровские сообщения плодить. По-хорошему, нужно использовать Registered Messages, а это хлопотно. Или поддерживать общий пул юзеровских сообщений... что порождает лишние связи между модулями... Можно, конечно, плюнуть и плыть по течению, но в большом проекте такой бардак рано или поздно приведет к проблемам... В общем, ваш выбор...
Ты сам-то понял, что чушь написал? Ну, будем считать это опиской ![]() |
Автор: Rickert 4.6.2008, 04:15 |
Да, что-то я относительно ON_MESSAGE прогнал ![]() Всем спасибо, solved ![]() |
Автор: dizzy1984 4.6.2008, 05:17 |
Написал по-проще для ясности, имелось в виду, что очередь значимых сообщений (идущих до WM_USER) уже будет обработана, останется только "надуманное" сообщение (WM_USER), которое, конечно, формально будет последним в той же очереди, но кого это волнует? Это как раз и нужно. |
Автор: dizzy1984 4.6.2008, 07:29 | ||
А на счет RegisterWindowMessage, это было дельное предложение. Вот более верный вариант :
|
Автор: Earnest 4.6.2008, 07:29 |
ОК, поясняю: ни в какую очередь SendMessage не идет - это, считай, прямой вызов CallWindowProc. |
Автор: dizzy1984 4.6.2008, 11:35 | ||
И в самом деле лопухнулся! Ведь знал же, что если SendMessage вызывается кодом процесса породившим окно-получатель, сообщение не ставится в очередь! Выходит, мой код ничем не лучше вызова процедуры из OnInitDialog. Ладно, тогда вот 3-я редакция. На этот раз с PostMessage :
Поставил флажки afxTraceFlags = traceAppMsg | traceWinMsg - вроде бы уж последнее-распоследнее. Здесь-то хоть не накосячил? |
Автор: Earnest 4.6.2008, 14:29 |
Увы... ![]() В студии 7 и выше просто не скомпилируется, а в более ранних - весьма вероятны проблемы в релизе, т.к. у обработчика должна быть другая сигнатура: LRESULT CTest2Dlg::OnProc (WPARAM, LPARAM); И еще: использовать для имени зарегистрированного сообщения GUID, мягко говоря, неудобно. Смысл ведь в том, чтобы из разных мест можно было к одному сообщению обратиться, не перевязывая код общими хедерами... так что сообщение должно быть типа "Test2Dlg_InitMessage"... Но это мелочи |