6

画面にモードレス ダイアログを表示し、その中に情報を表示したいと考えています。

ただし、次のように使用すると、いくつかの問題が発生します。

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

ダイアログが表示されているように見えますが、情報は何も描画されません。関数が終了したときにのみ、すべての情報を描画します。

モードレス ダイアログを変更して、情報がすぐに表示されるようにするにはどうすればよいですか?

4

4 に答える 4

6

できることがいくつかあります。

(1) CDialog::OnInitDialogメソッド内からダイアログにメッセージを投稿し、投稿されたメッセージのメッセージ ハンドラーで長い関数を処理することができます。そうすれば、最初にダイアログが表示され、その後長い関数が実行されます。

(2) 2 番目のオプションは、メッセージ ループにある程度の処理時間を確保することです。したがって、長い関数がある種のループである場合は、時折ProcessMessagesに呼び出しを追加して、メッセージ キューが空に保たれるようにします。

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

編集:そのような状況でスレッドを使用することは確かに可能ですが、そうすることには常にリスクと複雑さが伴うわけではありません。

GUIでスレッドを使用するということは、複数のメッセージ キューを処理しなければならないことを意味し、それはPostThreadMessageのような API を使用することを意味し、注意が必要な新しい一連の問題をもたらします。

このような問題の例については、次のリンクを参照してください。

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

どこで言う:

PostThreadMessage によって送信されるメッセージは、ウィンドウに関連付けられていません。原則として、ウィンドウに関連付けられていないメッセージは、DispatchMessage 関数によってディスパッチできません。したがって、受信者スレッドが (MessageBox または DialogBox で使用される) モーダル ループにある場合、メッセージは失われます。モーダル ループ中にスレッド メッセージをインターセプトするには、スレッド固有のフックを使用します。

私はZeus IDEでプロセス メッセージ アプローチを使用しています。これは、GUI がユーザーに応答し続けることを確認するのに非常にうまく機能します。また、実装が非常に簡単であるという利点もあります。

于 2008-12-22T10:49:44.393 に答える
5

OnInitDialog で、ワーカー スレッドを開始して計算を実行します。ワーカー スレッドからユーザー メッセージをポストして、ダイアログを更新します。

これは、いくつかの理由で ProcessMessages 実装よりも優れています。

  • 計算を行うためのコードは、それが属していない UI コードから切り離すことができます。

  • 実際の計算が実行されている間、UI は応答性を維持します。ProcessMessages では、単一の計算関数中に複数の UI を更新できますが、実際の計算中は UI が引き続きブロックされます。

ダイアログ コード:

#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);
    }
}
于 2008-12-23T14:14:41.640 に答える
2

経験則として、重い計算をGUIスレッドに配置しないでください。これはモードレスダイアログであるため、ダイアログはメッセージループを所有しません。ProcessMessage()ソリューションは機能しますが、IMOは正しい方法ではありません。私の提案は次のとおりです。1)OnInitDialog()で新しいスレッドを生成します。2)何か面白いことが起こったときに、別のスレッドにメッセージをダイアログに投稿させます。これらの興味深いことの1つは、作業が完了したことです。

ただし、これは適切な同期を実行する必要があることを意味することに注意してください。

于 2008-12-22T12:44:30.667 に答える
1

重い仕事を一度にやろうとしないでください。ダイアログが OnInitDialog の WM_APP 範囲にメッセージを投稿するようにします。WM_APP ハンドラーは、重い作業の一部を実行してから、別の PostMessage を実行して戻ることができます。このようにして、メッセージ ポンプが処理のチャンクの間にウィンドウ メッセージを処理できるようにします。

于 2008-12-24T04:36:28.123 に答える