Как я могу показать немодальное диалоговое окно и немедленно отобразить в нем информацию? - PullRequest
6 голосов
/ 22 декабря 2008

Я хочу показать немодальное диалоговое окно на экране и отобразить в нем некоторую информацию.

Однако, если я использую его следующим образом, у него есть некоторые проблемы:

function()
{
showdialog(XXX).
//heavy work.
update the dialog..
//heavy work.
update the dialog...
}

Кажется, диалоговое окно отображается, но оно не рисует никакой информации. Вся информация выводится только после завершения функции.

Как изменить немодальное диалоговое окно, чтобы оно сразу отображало информацию?

Ответы [ 4 ]

6 голосов
/ 22 декабря 2008

Есть несколько вещей, которые вы можете сделать.

(1) Вы можете опубликовать диалоговое окно сообщения изнутри метода CDialog :: OnInitDialog , а затем обработать длинную функцию в обработчике сообщений что разместил сообщение. Таким образом, сначала отобразится диалоговое окно, а затем запустится длинная функция.

(2) Второй вариант - убедиться, что цикл обработки сообщений получает некоторое время обработки. Поэтому, если ваша длинная функция представляет собой какой-то цикл, просто добавьте случайный вызов ProcessMessages , чтобы убедиться, что очередь сообщений остается пустой:

void ProcessMessages()
{
    MSG msg;
    CWinApp* pApp = AfxGetApp();
    while (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE))
    {
        pApp->PumpMessage();
    }
}

Редактировать: Конечно, возможно использование потоков в такой ситуации, но это не всегда без риска и сложности.

Использование потоков с GUI означает необходимость иметь дело с несколькими очередями сообщений, что в свою очередь означает использование API, например PostThreadMessage , и это создает новый набор проблем, с которыми следует опасаться.

Пример одной такой проблемы можно найти по этой ссылке:

http://msdn.microsoft.com/en-us/library/ms644946(VS.85).aspx

где это говорит:

Сообщения, отправленные PostThreadMessage, не связано с окном. Как общее правило, сообщения, которые не являются связанный с окном не может быть отправлено DispatchMessage функция. Поэтому, если получатель нить находится в модальном цикле (как используется MessageBox или DialogBox), сообщения будут потеряны. Перехватить сообщения в то время как в модальном цикл, используйте специфичный для потока крючок.

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

5 голосов
/ 23 декабря 2008

В OnInitDialog запустите рабочий поток для выполнения вычислений. Отправьте сообщение пользователя из рабочего потока, чтобы обновить диалоговое окно.

Это превосходит реализацию ProcessMessages по нескольким причинам:

  • Код для выполнения вычислений можно отделить от кода пользовательского интерфейса, где он не принадлежит.

  • Пользовательский интерфейс остается отзывчивым, пока выполняются фактические вычисления. ProcessMessages позволяет несколько обновлений пользовательского интерфейса во время одной функции расчета, но пользовательский интерфейс все еще будет заблокирован во время фактических расчетов.

Диалоговый код:

#define WM_NEW_COUNT (WM_USER + 0x101)

BEGIN_MESSAGE_MAP()
    ON_MESSAGE(WM_NEW_COUNT, OnNewCount)
END_MESSAGE_MAP()

BOOL CMyDialog::OnInitDialog()
{
    CWinThread* pThread = AfxBeginThread(MyCountFunc, this->GetSafeHwnd());
    return TRUE;
}

LRESULT CMyDialog::OnNewCount(WPARAM wParam, LPARAM)
{
    int newCount = (int)wParam;

    // m_count is DDX member, e.g. for label
    m_count = newCount;

    UpdateData(FALSE);

    return 0;
}

Рабочий поток:

UINT MyCountFunc(LPVOID lParam)
{
    HWND hDialogWnd = (HWND)lParam;

    for (int i=0; i < 100; ++i)
    {
        PostMessage(hDialogWnd, WM_NEW_COUNT, i, NULL);
    }
}
2 голосов
/ 22 декабря 2008

Как правило, тяжелые вычисления никогда не должны помещаться в поток GUI. Поскольку это немодальное диалоговое окно, оно не будет принадлежать циклу сообщений. Решение ProcessMessage () будет работать, но IMO - не правильный путь. Мое предложение: 1) Создать новый поток в OnInitDialog () 2) В отдельной ветке публиковать сообщения в диалоге, когда происходит что-то интересное. Одна из этих интересных вещей - то, что работа сделана.

Обратите внимание, однако, что это будет означать, что вам нужно выполнить правильную синхронизацию.

1 голос
/ 24 декабря 2008

Не пытайтесь выполнять свою тяжелую работу одновременно. Пусть диалоговое окно опубликует само сообщение в диапазоне WM_APP в OnInitDialog. Обработчик WM_APP может выполнить часть тяжелой работы, затем выполнить другое PostMessage и вернуться. Таким образом, вы разрешаете обработчику сообщений обрабатывать оконные сообщения между вашими фрагментами обработки.

...