Периодические задачи всего приложения с приложением Dialog Based MFC - PullRequest
3 голосов
/ 29 января 2010

В приложении MFC с интерфейсом с одним документом (MDI) или с интерфейсом с несколькими документами (MDI) я создал таймер приложения в представлении. Таймер будет работать до тех пор, пока приложение работает, и запускать некоторые периодические действия.

Как я могу сделать то же самое с приложением Dialog Based MFC?

  1. Должен ли я создать таймер потока (SetTimer с NULL HWND) и передать ему функцию обратного вызова?
  2. Должен ли я создавать рабочие потоки? Мой опыт работы с другими проектами был, когда я пытался отобразить некоторый графический интерфейс обратной связи из не-GUI / рабочих потоков, мне нужно развернуть свой собственный шаблон «делегат» / команда и «вызывающий делегат» / команда. Рабочий поток отправит сообщение (я думаю, что использование сообщения более безопасно, чем прямой вызов функции при работе через границу потока, CMIIW) в поток пользовательского интерфейса. и UI-поток будет вызывать делегат / команду. Если этого не сделать и убедиться, что окна / диалоги имеют правильного родителя, это приведет к странным действиям, таким как приложение внезапно исчезнет на заднем плане; Окно / Диалог, который отображается за текущим окном / диалоговым окном и приводит к тому, что текущее окно перестает отвечать на запросы / не щелкает. Возможно, я делал что-то не так, но при работе с потоками было так много проблем.

Есть ли лучшие практики для этого?

Ответы [ 4 ]

1 голос
/ 29 января 2010

Таймер также работает в диалоговом приложении, как приложение SDI или MDI.OTOH, таймеры (в основном) остатки от 16-битной Windows.Если вы хотите делать что-то периодически, рабочий поток, как правило, является лучшим способом сделать это (и да, Windows Mobile поддерживает несколько потоков).

Редактировать: в приложении на основе диалогов, главный диалог(по существу) всю жизнь приложения.Если вам не нужен таймер в течение миллисекунд между запуском приложения и созданием диалога или уничтожением диалога и выходом из приложения, просто присоедините его к диалогу.В противном случае вы можете прикрепить его к главному окну - которое MFC создает и уничтожает, даже если оно никогда не отображается.

0 голосов
/ 01 февраля 2010

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

Ваше базовое ванильное приложение MFC Dialog использует только один поток. Основной поток начинается с класса, производного от CWinApp. В методе InitInstance () он запускает диалог, используя CDialog :: DoModal (). Эта функция не возвращается, пока диалог не будет закрыт.

Во время работы диалога класс CWinApp не обрабатывает никаких сообщений, поэтому не видит WM_TIMER.

Есть много способов обойти это.

  1. Пусть первый диалог владеет таймером и делает все остальные диалоги его потомками. Это может быть хорошо, в зависимости от ваших требований к диалогу, но это может быть слишком ограничительным.

  2. Запустить первый диалог как немодальный, т.е. использовать Create () вместо DoModal (). Create () сразу возвращается (помещая диалог в другой поток). Затем вы можете создать цикл обработки сообщений в классе CWinApp и обработать там таймеры. Вам придется использовать таймеры потоков вместо оконных таймеров, так как класс CWinApp не имеет окна. (или вы можете создать скрытое окно, если это более удобно).

  3. Вы можете взломать цикл сообщений диалога и заставить его передавать сообщения в обработчик сообщений класса CWinApp. Это довольно сложно и не для слабонервных.

  4. Вы можете создать специальный поток таймера. Вы, вероятно, сделаете это из класса CWinApp до того, как он создаст диалог, но возможны другие стратегии.

Какие-нибудь из этих схем звучат так, как будто они соответствуют вашим потребностям? Если нет, возможно, вы сможете объяснить свои потребности более полно, и мы сможем найти что-то подходящее.

0 голосов
/ 29 января 2010

IMO, используйте таймер, если он решает проблему. Как вы упомянули, рабочий поток, взаимодействующий с пользовательским интерфейсом в MFC, может иногда доставлять больше хлопот, чем стоит.

Если проблема достаточно проста для таймера, вот что я бы использовал (Помните, ПОЦЕЛУЙ)

SetTimer не нужно передавать окно для работы, он может вызывать метод обратного вызова.

Вы можете использовать это в своем приложении - объявите в своем CWinApp (или где-либо еще)

static void CALLBACK OnTimer(HWND, UINT, UINT, DWORD);

Тогда в InitInstance звоните SetTimer(0, [eventid], [time period], OnTimer);

В OnTimer вы можете вернуться к экземпляру CWinApp через AfxGetApp() или theApp, поскольку существует только один.

0 голосов
/ 29 января 2010

Если вы используете мастер MFC для создания приложения на основе диалога, у вас, вероятно, есть скрытое окно просмотра, а также диалоговое окно. Окно представления создает диалог с DoModal (), который запускает диалог в том же потоке, эффективно приостанавливая окно представления.

Пока открыто диалоговое окно, окно просмотра не будет обрабатывать какие-либо события. Таким образом, если окно просмотра владеет таймером, оно не будет обрабатывать события таймера.

Самое простое решение - создать таймер в диалоговом окне и позволить диалогу обрабатывать сообщения таймера.

...