プログレスバーの作成・タイマの利用

プログレスバー・タイマ1
プログレスバー・タイマ2 プログレスバー・タイマ3

プログレスバーを持つ、ダイアログボックスを作成します。
プログレスバーが、0%から始まり、1秒おきに5%づつ増え、100%で止まるアプリケーションを作成します。

テキストの表示 - インコのWindowsSDK で作成したソースをもとに作成します。

ここでは、Reseditで作成する方法も説明します。

流れ

プログレスバーは、コモンコントロールのひとつです。コモンコントロールは他にも、ツリービューやリストビュー、ツールバーなどがあります。
コモンコントロールは、comctl32.dllというライブラリで提供されています。

コモンコントロールを使う場合は、下記1、2の両方を行って下さい。

1.commctrl.h をインクルード
windows.hをインクルードした後にインクルードしてください。

2.comctl32.lib を読み込む

WM_INITDIALOG

リストボックス - インコのWindowsSDK でも説明しましたが、WM_INITDIALOGは、ダイアログが作成されたときに、一度だけ発生するメッセージです。

1.InitCommonControls()でコモンコントロールの初期化
コモンコントロールを使う前にこの初期化が必要です。

2.プログレスバーを設定するのに、ウィンドウにメッセージを送る関数SendMessage()を使います。

lResult = SendMessage(
    HWND hWnd,      // 送信先ウィンドウのハンドル
    UINT Msg,       // メッセージ
    WPARAM wParam,  // メッセージ特有のパラメータ1
    LPARAM lParam   // メッセージ特有のパラメータ2
);

2.1.PBM_SETRANGEメッセージで、プログレスバー範囲を設定
コモンコントロールですので、commctrl.hをインクルードする必要があります。ライブラリにcomctl32.libを追加する必要があります。

lResult = SendMessage(
    (HWND) hWndControl, // プログレスバーのハンドル
    (UINT) PBM_SETRANGE,
    (WPARAM) 0,    // 0固定
    (LPARAM) MAKELPARAM(pb_min, pb_max)     // プログレスバー範囲の最小値をLOWORD、最大値をHIWORD
);

2.2.PBM_SETSTEPメッセージで、プログレスバー 1ステップの増分を設定します。
これもcommctrl.hをインクルードして、ライブラリにcomctl32.libを追加する必要があります。

lResult = SendMessage(
    (HWND) hWndControl, // プログレスバーのハンドル
    (UINT) PBM_SETSTEP,
    (WPARAM) pb_step,    // 1ステップの増分
    (LPARAM) 0,    // 0固定
);

3.SetTimer()で、タイマをミリ秒単位でセット

UINT_PTR SetTimer(
  HWND hWnd,              // ウィンドウのハンドル
  UINT_PTR nIDEvent,      // タイマのID
  UINT uElapse,           // タイムアウト値(ミリ秒単位)
  TIMERPROC lpTimerFunc   // TimerProcコールバック関数へのポインタ
);

上記のlpTimerFuncがNULLの場合は、タイマがタイムアップするごとに、 WM_TIMERメッセージに対する処理が実行されます。
それ以外の場合は、タイマがタイムアップするごとに、 TimerProcコールバック関数(タイマプロシージャ)が実行されます。
タイムアップした時の処理を、WM_TIMERメッセージで処理するか、TimerProcコールバック関数を新たに作成して、そこで処理するかの違いです。
ここでは、WM_TIMERメッセージで処理します。

WM_TIMER

WM_TIMERメッセージは、セットされたタイマがタイムアップした場合に発生するメッセージです。

1.プログレスバーが100%に達したときに、タイマを止める関数 KillTimer() を実行します。

BOOL KillTimer(
    HWND     hWnd,     // ウィンドウのハンドル
    UINT_PTR nIDEvent  // タイマのID
);

2.PBM_STEPITメッセージで、プログレスバーを1ステップ増分

lResult = SendMessage(
    (HWND) hWndControl, // プログレスバーのハンドル
    (UINT) PBM_STEPIT,
    (WPARAM) 0,    // 0固定
    (LPARAM) 0,    // 0固定
);

3.現在のプログレスバー増分を変数strに格納。

_stprintf_s()は、tchar.hで定義されており、文字セットがunicodeの場合は、swprintf_s()になり、 文字セットがマルチバイトのときは、sprintf_sになります。

_stprintf_s(a, MAX_SIZE, format, [c・・・])

この_stprintf_s()は、数式などを文字列に変換するものです。
文字列a に、制御文字列formatで示す形式でセットします。
この制御文字列には、%d(10進数の整数)、%s(文字列)、%f(小数)といったフォーマット指定子を含めることができます。
MAX_SIZE は、文字列a が確保するバッファのサイズです。
swprintf_s、sprintf_sはそれぞれ、swprintf、sprintfのセキュリティが強化されたものです。

4.SetWindowText()で、変数strを表示。
SetWindowText()は、 エディット - インコのWindowsSDK で紹介したSetDlgItemText()と同じ機能を持ちます。

BOOL SetWindowText(
    HWND     hWnd,     // ウィンドウのハンドル
    LPCTSTR lpString  // セットする文字列
);

リソースファイル

1.プログレスバーを使用するため、commctrl.hをインクルード。

2.プログレスバー[PROGRESS_CLASS]を追加。

PROGRESS_CLASSの代わりに、"msctls_progress32"と記述することができます。「" "」を忘れないで下さい。
この場合は、リソースファイルで、commctrl.hをインクルードする必要はありません。
ただし、"msctls_progress32"と記述した場合でも、Cソースファイルでは、commctrl.hのインクルードが必要です。

CONTROL         "", id, PROGRESS_CLASS, style, x0, y0, width, height

idコントロールID
style スタイル(要:commctrl.h)
PBS_SMOOTH : スムーズ(Lunaスタイルでは変化なし)
PBS_VERTICAL : 縦型のプログレスバー
x0プログレスバー左上のx座標
y0プログレスバー左上のy座標
widthプログレスバーの幅
heightプログレスバーの高さ

・Visual Studioのリソース ビュー、ResEditでの設定
ツールボックス(Toolbox)ウインドウの「Progress Bar」を選択すると、プログレスバーが作成できます。
「Static Text」は、テキストを挿入する際に使用します。

VCwin32アプリケーション4

ソースコードの入力

ソースコードは下記のように入れてください。

test.cpp
#include <windows.h>
#include <commctrl.h>
#include <stdio.h>
#include <tchar.h>
#include "resource.h"

#pragma comment(lib, "comctl32.lib")

#define pb_step 5
#define pb_min 0
#define pb_max 100

UINT iProg; // 現在のプログレスバーの位置

// このコード モジュールに含まれる関数の宣言を転送します:
BOOL CALLBACK DialogProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
          PSTR lpCmdLine, int nCmdShow )
{
    DialogBox(hInstance, TEXT("DIALOG_BOX"), NULL, DialogProc);
    return 0;
}

BOOL CALLBACK DialogProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    HWND hProg;
    TCHAR str[10];
    hProg = GetDlgItem(hWnd, IDC_PROGRESS1);
    switch (msg)
    {
        case WM_INITDIALOG:
            InitCommonControls(); 
            SendMessage(hProg, PBM_SETRANGE, (WPARAM)0, MAKELPARAM(pb_min, pb_max));
            SendMessage(hProg, PBM_SETSTEP, (WPARAM)pb_step, 0); 
            SetTimer(hWnd,IDC_TIMER, 1000, NULL);  /*1000[ms]タイマーイベント*/;
            break;
        case WM_TIMER:
            iProg += pb_step;
            if(iProg >= 100)
            {
                KillTimer(hWnd, IDC_TIMER); 
            }
            SendMessage(GetDlgItem(hWnd, IDC_PROGRESS1), PBM_STEPIT, 0, 0);
            _stprintf_s(str, 10, TEXT("%d %"), iProg);
            SetWindowText(GetDlgItem(hWnd, IDC_STATIC1), (LPCTSTR)str); 
            break;
        case WM_CLOSE:
            KillTimer(hWnd, IDC_TIMER); 
            EndDialog(hWnd, IDOK);
            break;
    }
    return FALSE;
}

resource.h

#define IDC_PROGRESS1 500
#define IDC_TIMER 1000
#define IDC_STATIC1 1
#ifndef IDC_STATIC
#define IDC_STATIC -1
#endif

Reseditで作成した場合は、これとは異なるソースコードになります。

test.rc
#include "resource.h"
#include <commctrl.h>

/////////////////////////////////////////////////////////////////////////////
//
// ダイアログ
//

DIALOG_BOX DIALOG 0, 0, 170, 62
FONT 9, "MS UI Gothic"
CAPTION "ダイアログ"
BEGIN
    CONTROL         "", IDC_PROGRESS1, PROGRESS_CLASS, 0, 29, 38, 123, 14
    LTEXT           "%", IDC_STATIC1, 88, 16, 29, 15
END

Reseditで作成した場合は、これとは異なるソースコードになります。