【VBA×WindowsAPI】不確定なプログレスバーを作成する

VBAでプログレスバーを使用する際、多くの場合、ループ回数や工程が決まっている処理に対して利用されるため、進捗状況をパーセンテージとして数値で表すことが可能です。しかし、場合によっては処理の進捗を数値化できないケースもあり、その場合はプログレスバーを進める処理を実装できません。

こうした場合に役立つのが「不確定型プログレスバー」です。このタイプのプログレスバーは、処理が進行中であることだけをユーザーに伝えるためのもので、進捗の具体的な割合を示す必要はありません。ただし、VBAの標準プログレスバーコントロールでは、不確定型プログレスバーの動作を実現することはできません。UserFormの既存コントロールを工夫して再現するのもありですが、WindowsAPIを利用することで、簡単かつ見栄えの良い不確定型プログレスバーを作成することが可能です。

不確定型プログレスバーの作成

プログレスバーは、処理や作業の進捗状況を視覚的に表現するためのUI要素です。特定のタスクが完了するまでの時間や進捗度をユーザーに伝える目的で使用されます。このプログレスバーには大きく分けて「確定型プログレスバー」と「不確定型プログレスバー」の2つの種類が存在します。

確定型プログレスバーは、処理のループ回数や工程が明確に決まっており、進捗を数値化できる場合に利用されるプログレスバーです。一方、不確定型プログレスバーは、Do~Loopのようにループ回数が明確でない処理のような、進捗を計算で求められない処理に使用されるプログレスバーです。

このうち不確定型プログレスバーはVBAの標準機能だけでは実装が難しいものですが、WindowsAPIを使うことで上動画のようにUserForm上に実装することができます。ただし、このプログレスバーはWindowsAPIを使って新たに生成されたコントロールのため、UserFormの標準コントロールとは違いオブジェクトとして存在はしません。そのため値変更や作成後の位置の変更、イベントの設定などは基本的には行うことができないので注意が必要です。(※バーの色も基本的には変更不可)

VBAで不確定型プログレスバーを作成するには下記のWindows APIを利用します。
それぞれ関数のより詳細な使い方の解説は各関数のリンクページを参照下さい。

icon-check-square FindWindow関数         :ウィンドウのハンドルを取得する
icon-check-square CreateWindowEx関数  :ウィンドウ(コントロール)を作成する
icon-check-square DestroyWindow関数    :ウィンドウ(コントロール)を破棄する
icon-check-square SendMessage関数       :ウィンドウにメッセージを送信する
icon-check-square GetDC関数                 :デバイスコンテキスト(DC)を取得する
icon-check-square ReleaseDC関数            :指定のDCを解放する
icon-check-square GetDeviceCaps関数     :デバイス情報(画面解像度)を取得する

「そもそもWindows APIって何?」という方はコチラ(メインページ)も併せて参照下さい。

サンプルコード

UserFormに不確定型プログレスバーを作成するためのサンプルコードは下記の通りです。
上画像の通り「Label1」コントロールを作成したUserFormのコードとして下記コードを使用してください。下記コードコピペ後、そのUserFormを表示するだけでLabel1の位置に不確定型プログレスバーが作成され、アニメーションが始まります。不確定型プログレスバーは確定型とは違い、アニメーションが無限にループするだけなので、処理の途中にカウントを増やすなどの処理は不要です。(※処理中にアニメーションが止まる場合は、ループ内にDoEventsを入れることで問題が解消します。)

コード解説

icon-edit ウィンドウハンドルを取得する

ウィンドウにはそれぞれを識別するためにウィンドウハンドルと呼ばれるIDが割り当てられています。WindowsAPIでウィンドウの情報を取得したり操作する際には、このウィンドウハンドルを使って行います。今回のケースでは、プログレスバーを作成する場所の情報として必要になります。

ウィンドウハンドルを取得する方法はいくつも存在しますがここでは常套手段のFindWindow関数を使ってウィンドウハンドルを取得しています。FindWindow関数は下記のように記載することで指定のクラス名もしくはウィンドウ名から該当のウィンドウへのハンドルを取得することができます。(UserFoemの場合はクラス名に「”ThunderDFrame”」、ウィンドウ名に「Me.Caption」で取得可能)

icon-code FindWindow関数 

hWnd = FindWindow(クラス名”, “ウィンドウ名”)

 

icon-edit 不確定型プログレスバー作成

Windowsにはツールバーやステータスバー、ツリービューをはじめとした「コモンコントロール」と呼ばれるコントロール群が登録されており、プログレスバーもこのコモンコントロールに含まれています。コモンコントロールを新規作成する場合はCreateWindowEx関数を使います。

引数は非常に多く、基本的には上記の通り記載すれば問題ありません。
このとき、値を変えることのある引数は第4~8引数で、それ以外は基本的に定数値です。

第4引数には作成するコントロールのウィンドウスタイルを入力していますが、不確定プログレスバーの場合は「PBS_MARQUEE」を設定する必要があります。この値を設定することでプログレスバーは「マーキースタイル」が適用され不確定プログレスバーとして設定することができます。

第5~8引数は作成するコントロールの位置と大きさを入力します。サンプルコードでは事前に作成しておいたLabelと同じ位置、サイズになるような値を入力しています。本関数の入力値の単位はピクセル(px)のため、UserForm上の単位ポイント(pt)を変換するための関数を通しています。位置調整のためにLabelを用意していますが、定数を直接入力しても問題ありません。

CreateWindowEx関数で作成したコントロールは不要になったら、DestroyWindow関数を使って明示的に破棄する必要があります。本関数を通さずに処理を終えてしまうとメモリリークを起こす原因となるため注意が必要です。(サンプルコードではTerminateイベントで実行)

icon-code SendMessage関数 

Call DestroyWindow(hWndDate)

引数として破棄するコントロール(ウィンドウ)のハンドルを入力します。CreateWindowEx関数は作成したコントロールのウィンドウハンドルを戻り値として返すため、その値をそのまま入力すれば作成した日付選択コントロールを破棄することができます。
 

icon-edit アニメーションの開始/停止

不確定型プログレスバーのアニメーションを開始するにはSendMessage関数を使って下記のように記載します。本処理を実行することで以降はプログレスバーのアニメーションが無限にループします。

icon-code  マーキーアニメーション開始 

Call SendMessage(hWndProg, PBM_SETMARQUEE, 1, dMilliseconds)

第1引数には作成したプログレスバーのウィンドウのハンドル、第2引数にはアニメーション設定するための定数値「PBM_SETMARQUEE」、第3引数にはアニメーションを開始するという意味の「1」、第4引数にはアニメーションの更新間隔をミリ秒単位で指定します。基本的には決まった値になってきますが、第4引数に関してはアニメーションの速度を任意で入力することが可能です。

基本的に処理が終了したらウィンドウそのものを閉じるため、あまり利用頻度は高くないですが、アニメーションを停止する際は開始時と同じくSendMessage関数を使って下記のように記載します。

icon-code  マーキーアニメーション停止 

Call SendMessage(hWndProg, PBM_SETMARQUEE, 0, 0)

停止の場合は第1,第2引数は開始と同じ値を入力し、第3,4引数はいずれも0を入力します。
 

関連情報

icon-share-square VBA×WindowsAPIまとめページ

その他のWindowsAPI関数は下記ページにまとまっているので合わせて参照下さい。

icon-share-square 参考

Microsoft公式:進行状況バー コントロールについて – Win32 apps

2024年12月1日Excel, VBA, Windows API

Posted by Lic