Last Updated 2002/06/06
Programming Tips Visual C++ MFC ダイアログ  索 引 
ダイアログアプリにプログレスバー
2002/06/06

もともと DOS や Win32 Console アプリで作成されているものを GUI に変更する.
ダイアログベースにしてプログレスバーで処理進行状況を表示する.

BOOL CxxxApp::InitInstance()
{
....
    CCatLogDlg dlg;
    m_pMainWnd = &dlg;

//  int nResponse = dlg.DoModal();      // これを変更
    int nResponse = dlg.Create(IDD_CATLOG_DIALOG);

    Main();

    dlg.DestroyWindow();

    return FALSE;
}


void CxxxApp::Main()
{
    CCatLogDlg *dlg;
    dlg = (CCatLogDlg *)m_pMainWnd;
    CProgressCtrl *prog;      // ダイアログに貼り付けたプログレスバー
    prog = &dlg -> m_pgrsRun;

    while( 1 ) {
    // ここでファイル整形処理
    ....
        prog -> SetPos(50);   // 進行状況をセット

    // メッセージ処理
        MSG msg;
        while( ::PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
            ::TranslateMessage( &msg );
            ::DispatchMessage( &msg );
        }

    }
}


こんな感じで可能だが,もっと MFC を活用,スレッドを活用する方法を考えてみる.
もとの DOS ベースの処理をワーカースレッドとして起動すれば,DOS ベースのソースがほとんど使えて,UI とファイル処理とに明確に分離できる.

1. ファイル変換処理ルーチンをクラスに依存しない形で用意する
(ダイアログクラスのstaticメンバ関数としても良い)
2. プログレスバー進捗処理,ファイル変換処理ルーチンの呼び出しはダイアログクラス内で行う.
3. ダイアログクラスの OnInitDialog(WM_INITDIALOG) にて,自分自身に処理開始の PostMessage する.
4. ダイアログクラスの処理開始ルーチンでファイル変換処理ルーチンをスレッドとして呼び出す.
5. ファイル変換処理ルーチンは定期的に呼び出し元のダイアログクラスに進捗具合を PostMessage で通知する.通知を受け取ったダイアログクラスは,その度にプログレスバーを更新する.
6. スレッド側から処理終了の通知を受け取ったダイアログクラスは,任意のタイミングで EndDialog して終了する.

                                         起動
                     起動                (中断)
+------------------+ →→ +------------+ →→ +----------------+
| アプリケーション |      | ダイアログ |      | file converter |
+------------------+ ←← +------------+ ←← +----------------+
                     return              処理進行状況報告
                                         return

また,以下のような構成であれば,よりモジュールの分離が進められる.

                     起動
                     プログレスバー更新依頼
                     終了依頼
+------------------+ →→ +------------+
|                  |      | ダイアログ |
|                  | ←← +------------+
|                  | 処理起動依頼
|                  | (処理中断依頼)
|                  | return
| アプリケーション |
|                  | 起動
|                  | (中断)
|                  | →→ +----------------+
|                  |      | file converter |
+------------------+ ←← +----------------+
                     進行状況報告
                     return

変更するとこんな感じになる.

-- CTESTDlg.h --
...
#define WM_USER_RUN    (WM_USER + 100)
----------------

ユーザーメッセージを define します.

-- CTESTDlg.cpp --
...
BEGIN_MESSAGE_MAP(CTESTDlg, CDialog)
    //{{AFX_MSG_MAP(CTESTDlg)
...
    //}}AFX_MSG_MAP
    ON_MESSAGE(WM_USER_RUN, OnMyMessage)
END_MESSAGE_MAP()

BOOL CTESTDlg::OnInitDialog()
{
...
    AfxBeginThread(MyThreadProc, m_hWnd);

    return TRUE;
}

LRESULT CTESTDlg::OnMyMessage(WPARAM wParam, LPARAM lParam)
{
    m_prgsRun.SetPos(wParam);

    return 0;
}

UINT MyThreadProc( LPVOID pParam )
{
    HWND hWnd = (HWND)pParam;

    while( 1 ) {
    // ここでファイル処理
        ::PostMessage(hWnd, WM_USER_RUN, 50, 0);
    }

    return 0;
}

------------------


参照
前後のTips
ダイアログアプリにプログレスバー

DSS ProgrammingTipsCGI Ver2.02