プログレスバーを作る為のコード&解説
前回記事ではプログレスバー(ユーザーフォーム)の使用感が分かる動画を見ていただきました。
イメージ(進捗表示)は提供できました。続いてコードやフォーム等の実態を提供していきます。
タイトルにもある様にユーザーフォームについて勉強する事になります。
コードの記述方法やフォームの動作が分かる様になるとVBAで出来る事の幅が広がります。
実際にフォームを用意してコードと連動させプログレスバーを動かせるようにしていきます。
一連の作業を紹介することになりますので少々長くなります。可読性を上げるために目次のリンク機能をご活用ください。
関連記事
前回記事です。プログレスバーの概要、動画を用意しております。
この本で勉強しました
ユーザーフォームは本やネットでの情報が本当に少ないので良い情報源を確保するのが難しいです。
そのような環境の中で私のおすすめの書籍を紹介します。
各種リンク先の試し読み等で確認いただくとかなり深いところまで勉強できる事がわかります。
こちらの書籍は少し大きめの仕様となっております。取り回しの良さを考え電子書籍をおすすめします。
PC内でVBEと横並びに配置しVBAを書く事で作業性が上がります。ご検討ください。
画像の左下にあるようなシンプルなデザインのフォームの中にプログレスバーを用意します。
余談ですが「プログレスバー」は「進捗バー」という呼び方もある様です。なんとなくイメージは共感できます。
フォームの作り方
一連のシリーズの中で説明しています。ユーザーフォームを実装するにあたりどんな対応が必要なのか分かります。
リンク先URLの内容を確認しなくても分かる様にこの記事でもフォームを用意する方法を解説する事にします。
各モジュールの追加
まずはユーザーフォームを1つ表示させます。
VBEで標準モジュールを表示させるときの作業と同じです。
標準モジュールのすぐ上の選択肢がユーザーフォームです。
ひとまずユーザーフォームを1つ表示させておきましょう。
加えて標準モジュールも1つ使いますので表示させましょう。
最終的なプロジェクトエクスプローラの状況です。
フォームのツリーにUserForm1が1つです。
標準モジュールのツリーにはModule1が1つです。
フォームにコントロールを追加する
コードウインドウにあるフォームを選択します。
一緒にツールボックスが画面上に表示されます。
まずはデフォルトのコントロールでは足りない分を追加します。
以降は以下コントロールをフォーム上に展開します。
ツールボックスが消えてしまったときはこちらをご覧ください。
プログレスバーのコントロールを表示させます。
ツールボックスの上で右クリック。
「その他のコントロール(A)」を選択。
Microsoft ProgressBar Contorol ,Version6.0を選択。
OKボタンを押下。
これでコントロール上にアイコンが表示されます。
他にもいろいろな機能がありますので別途試してみてください。
各コントロールはツールボックスでアイコン選択後フォームをクリックすると形状が展開されます。
配置や大きさ、名前についてはプロパティウインドウから指示をします。
コントロールのカスタマイズ
各コントロールをカスタマイズしましょう。
まずはプロパティウインドウを使います。
デフォルトだとVBEの左下に配置されています。
表示がない方はVBEの「表示タブ」内をご覧ください。
プロパティウィンドウは各コントロールの属性を表示しています。
値を変える事でカスタマイズできます。
ラベルの属性を見たい時はラベルをクリックしましょう。
するとプロパティウインドウに属性が表示されます。
以下画像はフォームを選択した時の画像です。
すでにカスタマイズされている要素もあります。ご注意下さい。
分かりにくいかもしれないのでガイド(サンプル)を用意しました。
フォーム、ラベル、プログレスバー、コマンドボタンの属性を以下添付ファイルの様に変更(入力)してください。
ダウンロード後インストールするものではないです。プログレスバーとして使うフォームの内容を数値化したデータです。
画像のような配置になっていれば正解です。
簡単な仕様ですがシンプルで見やすくて良いですよね。
これで進捗状況を見た目で判断する準備が整いました。
ステータスバーのような表示をフォームで準備することができましたね。
なお配置だけでは各コントロールに名前が付いているのか分かりません。
オブジェクト名も確実に書き換える様ご注意ください。
各オブジェクト名がダウンロードファイルと異なる際はコードを実行させる時にエラーになります。
データシート
続いてデータシートの状況をご覧ください。ここには1万行×7列の個人情報風の情報が並んでいます。
用意するコードの仕様
このセルの値を1つ1つSelectするというコードを用意しました。このようなコードを用意したのには理由があります。
程よく手数のかかる作業でプログレスバーの動きを確認出来る様なコードが用意したかった為です。
私がセルに値を入れている理由は値の増減でデータ量を変えられる為です。
皆様各自でデータを用意するのが面倒であればループに絶対値を記入してください。
セルをSelectしてるだけですので値は無くても(絶対値があれば)コードは組めます。
コード
今回のコードは長いです。いざ書こうと思うと大変です。
コードを選択する事でコピー出来る様にしておきましたので必要に応じて使用ください。
書く場所
結論から申し上げますと今回は以下2点です。
- UserForm1(フォーム)
- Module1(標準モジュール)
この2つのモジュールにコードを書く事になります。
書き方
ユーザーフォームにコードを書く方法です。
プロジェクトエクスプローラ内でフォームを選択後右クリック。
すると「コードの表示」が出てきます。
ここにコードを書きましょう。
標準モジュールには通常の方法でコードを記入しましょう。
コード
ユーザーフォームに記載するコードはこちらになります。
(Option Explicitは必要に応じてコピーしてください)
Option Explicit
'キャンセル処理用フラグ
Public IsCancel As Boolean
'初期化
Private Sub UserForm_Initialize()
'キャンセルフラグにFalseを設定
IsCancel = False
End Sub
'キャンセルボタンクリックイベント
Private Sub BtnCancel_Click()
'キャンセルフラグにTrueを設定
IsCancel = True
End Sub
標準モジュールには以下コードを記載してください。メインのプロシージャ(プログラム)です。
こちらのコードは少し長いのでコピーボタンを用意しておきます。
Option Explicit
'いつもの様にあえて変数は日本語を使っています
Sub プログレスバー()
'**********************************************************************
'1_変数の定義
Dim 最終行 As Long
Dim 最終列 As Long
Dim 行 As Long
Dim 列 As Long
'フォームで使う変数
Dim percent As Long 'frmPBで使用 処理の進捗
Dim count As Long 'frmPBで使用 変数percentの分母
Dim p As Long: p = 1 'frmPBで使用 変数percentの分子
'**********************************************************************
Application.ScreenUpdating = False
'**********************************************************************
'2_データ範囲取得
最終行 = Cells(Rows.count, 2).End(xlUp).Row
最終列 = Cells(6, Columns.count).End(xlToLeft).Column
'**********************************************************************
'3_PB初期設定
'フォームで使う変数percentの分母に値をセット 変数の後のマイナスは開始列までの値
count = 最終列 - 1
'FrmPBを表示
frmPB.Show vbModeless
'フォームの表示位置を決める(適当)
frmPB.StartUpPosition = 0
frmPB.Top = 220
frmPB.Left = 550
'フォームの最小値を設定
frmPB.ProgressBar1.Min = 1
'フォームの最大値を設定
frmPB.ProgressBar1.Max = count
'フォームの現在値を設定
frmPB.ProgressBar1.Value = 1
'アイコンを待機中に固定
Application.Cursor = xlWait
'**********************************************************************
'4_ループ処理
'今回のコードはただセルを選択するだけ
'その間でキャンセルボタンが押された時の処理待ちや進捗の値を更新している
For 列 = 2 To 最終列
For 行 = 6 To 最終行
'セルを選択するだけ
Cells(行, 列).Select
'5_キャンセル処理と進捗確認
'進行中の処理をキャンセルした時の処理とfrmPBに進捗度を表示させる為の処理
'進行中の処理ををキャンセル
If frmPB.IsCancel = True Then
'フォームを閉じる
Unload frmPB
'マウスカーソルをデフォルトに戻す
Application.Cursor = xlDefault
MsgBox "処理を中断しました"
End
'途中までの結果は無しにして処理を終了
End If
'frmPBに進捗度を表示
If frmPB.ProgressBar1.Min <= p And _
frmPB.ProgressBar1.Max >= p Then
'フォームのLabel表示を更新
percent = CInt(p / count * 100)
frmPB.lbl1.Caption = percent & "%完了"
'フォームの値を更新
frmPB.ProgressBar1.Value = p
'フォームに値をセットする為のコード
'コードの実行から一時抜けてVBA側に制御を戻して進捗表示をフォームに表示させる
'DoEventsをどれだけ拾うかはデータ量次第で調整
'以下コードは1列分の処理を終了したところでDoEventsが走る様に設定
If 行 = 最終行 Then
DoEvents
End If
End If
Next
p = p + 1
Next
'**********************************************************************
'6_後処理
'フォームを消す
Unload frmPB
'マウスカーソルをデフォルトに戻す
Application.Cursor = xlDefault
'**********************************************************************
Application.ScreenUpdating = True
MsgBox "作業完了", vbInformation, "確認"
End Sub
今回は単純なコードです。「ただセルをSelectするだけ」というコードです。
プログレスバーの動きを見る為にある程度時間がかかる処理をさせる為この様なコードを用意しています。
解説
ではここからコードの解説をしていきます。
フォーム
プロシージャを2つ用意しています。
- Initializeプロシージャ
- IsCancelプロシージャ
Initializeプロシージャ
フォームが立ち上がる(起動する)前に変数 IsCancel に False を設定するプロシージャです。
IsCancelプロシージャ
もう1つはフォームのキャンセルボタンが押された際に実行されるプロシージャですね。
変数IsCancel に True が代入されます。
標準モジュールのコード内で変数 IsCancel に True が入った時の処理を担当します。
マウスのカーソルをぐるぐるから元に戻しメッセージボックスを出してから処理を止めます。
標準モジュール
標準モジュールのコードは以下6つの構成から成り立っています。
- 1変数の定義
使用する変数を定義します
- 2データ範囲取得
リストの範囲を確定させるための作業をします
- 3PB初期設定
プログレスバーに初期値をセットします
- 4ループ処理
作業を繰り返します
- 5キャンセル処理と進捗管理
以下詳細をご覧ください。
- 6後処理
カーソルを元に戻す等作業完了に向けて準備をします
以降構成に従って手順を解説していきます。
1_変数の定義
変数の宣言(定義)です。コード内で使う変数とプログレスバーで使う変数を宣言しておきます。
Variant型でも可能ですが極力データ型は使用するデータに合った型を用意してください。
2_データ範囲取得
リストの最終行と最終列を探しに行きます。
リストの最終行を取得する為のコードについては別記事で詳しく書いています。必要に応じてご覧ください。
3_PB初期設定
ユーザーフォームfrmPBの各種プロパティに値をセットします。
フォームの表示位置のTopとLeftは各自のPCで調整してください。
プロシージャの長さが気になる時はこの部分だけサブルーチンで作っても良いですよ。
4_ループ処理
ひたすら値をSelectです。
この4番の作業の中に5番の「キャンセル処理と進捗確認」が配置されています。
5_キャンセル処理と進捗確認
対象件数が思ったより多くなり処理を途中でキャンセルしたい時はユーザーフォームのキャンセルボタンを押します。
キャンセルボタンを押すとフォームのコードで変数 IsCancel の値を変更しコードを中断させます。
変数 IsCancel が False のうちはコードを実行し続けます。
キャンセルボタンが押されて変数 IsCancel が True になったらコードを抜けます。
是非ご自身でコードを書いて動きを確認してみてください。
進捗率について
進捗確認は全体の仕事量に対して現状何%進んだのかを計算してラベルを書き換えています。
フォームにラベルを用意した際文字数より大きめの範囲を指定したのはこの為です。
単純に変数同士を割り算して比率を出して計算するというだけです。
最初は「処理中」という値が入っています。
進捗表示の為に数値に変わるのでCInt関数を使って文字列が入るはずのラベルを数値に変えています。
ループ処理の中にキャンセル処理と進捗確認を入れ込む事で以下の様に立ち回るという構造です。
- ループが進めば進捗率が上がる
- キャンセル処理が入ればループの途中で処理が止まる(処理を抜ける)
コードの中断について
最後にDoEventsメソッドです。DoEventsは「なんかあったらどうぞ」です。
「裏でたまってた処理あったらやってしまってください」という関数です。
コードの70行目から72行目あたりでコードでラベルの進捗率を変えたりプログレスバーの値を変えてます。
しかしScreenUpdatingが効いているのでコードが走っている間は表示は変わりません。
そんな中でもフォームの表示だけはリアルタイムに操作したいです。
DoEvents関数を使ってできるだけリアルタイム表示に近づける
矛盾が起こる中でこの矛盾を解決させるのがDoEventsです。
走ってしまったコードの処理から抜けて一旦VBAに処理(制御)が返ってきます。
DoEvents関数が実行される際フォームに反映されていないラベルの進捗率を実態に合わせて変えています。
DoEvents関数はキャンセルボタンの処理にも関わる
キャンセルボタンが押された時の処理もDoEventsが実行されたタイミングで稼働します。
私が用意したコードでは77行目の条件分岐の時に状況に応じてDoEventsが実行されます。
列は7列ですのでプログレスバーの表記は6回変わって7回目に変化する時は作業完了という事です。
DoEventsの使用回数をコントロールする理由
なんでこんなことをするのかと言いますとDoeventsは多用するとコードが遅くなります。
前回記事はバーの進みを遅くしたかった為行毎にDoEvents関数が発生する様にしています。
実際使う時はある程度サクッとバーが進まないと気持ち良くないです。
DoEventsが走る回数をコントロールしたという次第です。
ここは使い方や対象のデータ量でも変わります。
各自でDoEventsを通過する回数をコントロールしてください。
6_後処理
フォームを見えない様にしたりマウスカーソルを元に戻す作業をします。
作業終了のメッセージボックスを表示させる等後処理を行います。
ポイント
コードの考え方や実行環境について解説します。
1_作業の始点と終点を何にするのか決める
「プログレスバーの0%から100%を何で取るか」がポイントです。作業の始点と終点を何にするのか決めましょう。
今回はセルを対象にしているのでセルのSelectが進めば進捗は上がっていきます。
進捗率の分母と分子を何で取るのかが分かる様になるとコードをマスターしたと思っていただいて良いです。
すぐには難しいのでプログレスバーをご自身の仕事の中に盛り込んでいただく過程の中で使用感を掴んでください。
2_実行ボタンを用意しましょう
シートにボタンを用意してマクロを実行してみましょう。これでマクロが分からない方でもマクロを実行できます。
ボタンの作り方は非常に簡単です。詳細は以下リンクをご覧ください。
オートシェイプでボタンを作るボタンの作り方についてはコチラをご覧ください
まとめ
ではまとめに入ります。プログレスバーを作成するための一連の流れを見ていただきました。
今回の記事は内容も文章も多くなってしまいました。申し訳ございません。
非常に大変な作業ですがプログレスバーを作っていただくと以下のようなメリットがあります。
- 作業の進捗も分かるようになる
- マクロの処理を途中で抜けられる
- ユーザーフォームを勉強する為のステップとして最適
などなど良い事だらけです。ただし少し難しいので根気よく勉強をすすめてください。