プログラム実行時にどこまで進んだか、あとどれくらい時間がかかるのか表示させましょう!
ユーザーに使ってもらうことも視野に入れましょう!
ユーザーフォームで処理状況を表示しながら、バックグラウンドでプログラムを実行します
ユーザーフォーム作成
まず、ユーザーフォームを作成しましょう!
VBEから
挿入→ユーザーフォーム
オブジェクト名UserForm1が作成される
ツールボックスも表示しておきましょう
表示されない場合は
表示→ツールボックスを選択する
プロパティウインドウのフォームの項目変更
⇒
オブジェクト名:UserForm1→frmTestに変更
Caption :UserForm1→実行中…に
コマンドボタン追加
ツールボックスからコマンドボタンを選択して、フォームにドラッグする
オブジェクト名:btnClose
Caption:閉じる
同様にテキストボックスを追加する
オブジェクト名:txtJyoukyou
ラベルを追加
オブジェクト名:変更なし(プログラムに使わないので)
Caption:回目/10000回中
Fontサイズ:18
その他変更
画面を見ながら、位置や大きさを変更する
Font :フォントを変更したり、フォントサイズを変更します
TextAlign:文字の位置 センタリングを選びます
フォームの表示/非表示
フォームの表示
作成したフォームを表示してみましょう!
標準モジュールに以下を追加するだけです
ユーザーフォーム名.Show
frmTest:作成したフォーム名
Show:ユーザーフォームを表示
標準モジュール
Sub Test()
frmTest.Show
End Sub
フォームの非表示(フォームのアンロード)
Unload ユーザーフォーム名
フォームの閉じるボタンをダブルクリック
フォームのプログラム
Private Sub btnClose_Click()
End Sub
と表示されるので、
(btnCloseは作成したコマンドボタンのオブジェクト名)
Private btnClose_Click()
Unload frmTest
End Sub
標準モジュールのTestを実行し、フォームを表示します
表示されたフォームの閉じるボタンをクリックし、フォームを閉じます
フォームを開き・閉じることができましたか?
フォームのプログラム作成
フォームのコードの表示方法
frmTestをクリックして、表示からコードを選択(F7キーでも)
または、frmTestを右クリックして、コードの表示選択
先程作成したフォームのプログラムが表示されましたか?
フォームのプログラム
フォームが表示された時の処理を追加していきます
コードウインドウの左上
オブジェクトボックスからUserFormを選択し、
コードウインドウの右上
プロシージャボックスからActivateを選択
UserForm_Activateが作成されましたね!
これがユーザーフォームが表示された時、実行されるプログラムです
このUserForm_Activateからmainルーチンを呼び出します
このmainに時間のかかる処理を書く
(ここに直接プログラムを書いてもOKですが、
時間のかかる処理ですから通常ものすごい長いプログラムのはずです)
Private Sub btnClose_Click()
Unload frmTest
End Sub
Private Sub UserForm_Activate()
Call main
End Sub
標準モジュールプログラムの作成
標準モジュールのプログラム
標準モジュールにmainルーチンを書きます
ここに状況を表示させるプログラムを追加します
今回は10000回の処理中どこまで進んだかを表示!
frmTest.tと書くと候補が表示されます
作成したテキストボックスtxtJyoukyouを選び、
続けて.vと書き、候補からValueを選ぶ
frmTest.txtJyoukyou.Value = iとして、
txtJyoukyouに処理の状況(iの値)を表示します
描画を更新するためには、DoEventsが必要です
DoEventsがなければ、状況表示ができません(あっという間に終わってしまう)
コメントアウトして実行してみてください!(DoEventsの意味がわかるでしょう~)
Sub main()
Dim i As Long
For i = 1 To 10000
DoEvents 'OSに処理を返す(画面描画を更新)
frmTest.txtJyoukyou.Value = i
Next i
End Sub
F5キーを押して、Testを実行してみましょう
フォームがアクティブになった時に、mainルーチンが呼び出され、
作成したフォームのテキストボックスに処理状況が表示されます
Sub Test()
frmTest.Show
End Sub
実行ボタン作成
Excelからマクロを実行できるように
実行ボタンを作成し、
frmTestを表示するTestと紐づけます
ボタンを押して実行してみましょう!
閉じるボタンの変更
処理の途中で、閉じるボタンを押すと途中で終了し、フォームも消えてしまいます
続きを実行したいことありますよね
やめるのやめたい~
閉じるボタンをもう少し修正しましょう!
閉じるボタンを押された時の処理
btnClose_ClickにMsgBoxで”ほんとに終了していいの?”ときいてみましょう!
MsgBox(表示メッセージ[,ボタン][,タイトル])
ボタンにvbYesNo(4)を指定します
【はい】【いいえ】ボタンを表示します
MsgBox(“処理を中止しますか?”, vbYesNo)
MsgBoxの戻り値を取得することにより、閉じる判断ができる
MsgBoxの戻り値
戻り値が【はい】vbYes(6)かどうか判断し
vbYesでなければ、フォームを閉じずにExit
Private Sub btnClose_Click()
Dim CloseYesNo As Long
CloseYesNo = MsgBox("処理を中止しますか?", vbYesNo)
If CloseYesNo <> vbYes Then Exit Sub
Unload frmTest
End
End Sub
フォームが消去されても、EXCELは実行され続けますので、
プログラムを終了させるため、Unload フォームの後に、Endを入れましょう
はい:プログラム終了
いいえ:プログラム続行
終了処理
処理が終わっても、MsgBoxが表示される
これいらないよね!
処理が終了したら、
MsgBoxを表示して、フォームを消去します
UserForm_Activateかmainどちらかに加えてください…どちらがいいかな?
Private Sub UserForm_Activate()
Call main
'処理終了のメッセージを表示
MsgBox "処理が終了しました。"
'フォームをアンロードする
Unload frmTest
End Sub
Sub main()
Dim i As Long
For i = 1 To 10000
'OSに処理を返す(画面描画を更新)
DoEvents
frmTest.txtJyoukyou.Value = i
Next i
'処理終了のメッセージを表示
MsgBox "処理が終了しました。"
'フォームをアンロードする
Unload frmTest
End Sub
mainには終了の処理は関係ないので、
UserForm_Activateに入れる方がいいかなと思います
お好みで…
Module1
Sub Test()
frmTest.Show
End Sub
Sub main()
Dim i As Long
For i = 1 To 10000
DoEvents 'OSに処理を返す(画面描画を更新)
frmTest.txtJyoukyou.Value = i
Next i
End Sub
frmTest
Option Explicit
Private Sub btnClose_Click()
Dim CloseOkNo As Long
CloseOkNo = MsgBox("処理を中止しますか?", vbYesNo)
If CloseOkNo <> vbYes Then Exit Sub
'フォームをアンロードする
Unload frmTest
End
End Sub
Private Sub UserForm_Activate()
Call main
'処理終了のメッセージを表示
MsgBox "処理が終了しました。"
'フォームをアンロードする
Unload frmTest
End Sub
モーダルとモーダレス
今までは、モーダルでプログラムを組んできました
フォームを表示している間(Show~Unloadまで)、EXCELを操作できません
状況表示している間に画面をクリックしてみてください
”ポワンポワン”とすべての操作ができません
modalとは…
モードがある状態。つまり、システムが特定の機能の使用に制限された状態。
ユーザーが自由に操作を行えなくなることと、モード別に機能の意味や振る舞いが変化することから、ユーザーインターフェースのデザインでは、できる限りモードを設けないほうがよいとされる。
modelessとは…
モードがない状態。ユーザーインターフェースをデザインする際に目指すべき状態。
https://www.sociomedia.co.jp/326
状況に依存した機能制限がなく、自由な手順でタスクを進行することができ、
かつ特定の操作がシステムによって常に一定に解釈される状態。
ユーザーインターフェースの観点からモードレスの方が推奨されているのですね~
frmTest.Show vbModal モーダル(規定値)
frmTest.Show ←今まではこれ!
vbModalは、既定値ですので、省略するとモーダルとなります
ここまでのモーダルプログラム
Module1
Option Explicit
Sub Test()
'frmTest.Showでも可
frmTest.Show vbModal 'モーダル(規定値)
End Sub
Sub main()
Dim i As Long
For i = 1 To 10000
DoEvents 'OSに処理を返す(画面描画を更新)
frmTest.txtJyoukyou.Value = i
Next i
End Sub
frmTest
Option Explicit
Private Sub btnClose_Click()
Dim CloseOkNo As Long
CloseOkNo = MsgBox("処理を中止しますか?", vbYesNo)
If CloseOkNo <> vbYes Then Exit Sub
'フォームをアンロードする
Unload frmTest
End
End Sub
Private Sub UserForm_Activate()
Call main
'処理終了のメッセージを表示
MsgBox "処理が終了しました。"
'フォームをアンロードする
Unload frmTest
End Sub
frmTest.Show vbModeless モードレス
フォームを実行中でも、EXCELの操作ができます
フォームを実行中でも、EXCELの操作ができるので、
フォーム名.Show vbModelessの後にプログラムを置いて実行させることができます
プログラムは以下の様にSimple!!
フォームのプログラムはbtnClose_Clickのみ
UserForm_Activateは要らなくなりました
モードレスプログラム
Module1
Option Explicit
Sub Test()
'frmTest.Show vbModal 'モーダル(規定値)
frmTest.Show vbModeless 'モードレス
Call main 'フォームを表示した後にExcelのプログラムが書ける
'処理終了のメッセージを表示
MsgBox "処理が終了しました。"
'フォームをアンロードする
Unload frmTest
End Sub
Sub main()
Dim i As Long
For i = 1 To 10000
DoEvents 'OSに処理を返す(画面描画を更新)
frmTest.txtJyoukyou.Value = i
Next i
End Sub
フォーム
Option Explicit
Private Sub btnClose_Click()
Dim CloseOkNo As Long
CloseOkNo = MsgBox("処理を中止しますか?", vbYesNo)
If CloseOkNo <> vbYes Then Exit Sub
'フォームをアンロードする
Unload frmTest
End
End Sub
モーダル
フォーム名.Show
↓
UserForm_Activateに
メイン処理を呼び出す Or
メイン処理を書く
(メイン処理の中で状況表示)
↓
Unload フォーム名
終了ボタンを押された時 Or
メイン処理が終了したとき
モーダレス
フォーム名.Show vbModeless
メイン処理を呼び出す Or
メイン処理を書く
(メイン処理の中で状況表示)
↓
Unload フォーム名
終了ボタンを押された時 Or
メイン処理が終了したとき
私見ですが、別ファイルを開いたり、他のシートをアクティブにできるので、
プログラムに注意が必要なのかも…?
ActiveWorkBookとかActiveSheetとかいう指定は避けた方がいいのかも…と思う
ThisWorkbookは大丈夫なのかな?
フォーム名.Repaint
Repaint メソッドは、指定されたフォームに対して、
画面の更新操作がある場合はそれを実行します
また、Repaint メソッドは、更新に伴って、フォーム上のコントロールの再計算も行います
どちらかでいいと思うのですが、両方書いてもいいかな?色々と試してください
Repaint入れると、ちらつく気がするのですが…
For i = 1 To 10000
'OSに処理を返す(画面描画を更新)
DoEvents
frmTest.txtJyoukyou.Value = i
'画面の更新操作
frmTest.Repaint
Next i
DoEvents:動作の安定性
Repaint :処理の速さ
動作の安定性ではDoEvents関数が勝り、処理の速さではRepaintメソッドが勝ります。https://excel.syogyoumujou.com/form/1_27.html
仮想処理状況を表示
仮想処理状況を表示するPG作成しました
実行してみてください
フォーム
オブジェクト名:frmTest
Caption:実行中…
コマンドボタン
オブジェクト名:btnClose
Caption:閉じる
テキスト
オブジェクト名:txtJyoukyou
ラベル
オブジェクト名:lblJyoukyou
Caption:なし
オブジェクト名:変更なし
Caption:回目/10000回中
モーダルVer.
Module1
Option Explicit
Sub Test()
frmTest.Show
End Sub
Sub main()
Dim i As Long
'ここにFile 読み込み処理を書く
Cells(8, 5) = "File 読み込み中"
frmTest.lblJyoukyou.Caption = "File 読み込み中"
For i = 1 To 3000
'OSに処理を返す(画面描画を更新)
DoEvents
Cells(10, 5) = i
frmTest.txtJyoukyou.Value = i
'frmTest.Repaint '画面がちらつくのでコメントに
Next i
'ここに計算処理実行処理を書く
Cells(8, 5) = "計算処理実行中"
frmTest.lblJyoukyou.Caption = "計算処理実行中"
For i = 3001 To 7000
'OSに処理を返す(画面描画を更新)
DoEvents
Cells(10, 5) = i
frmTest.txtJyoukyou.Value = i
'frmTest.Repaint '画面がちらつくのでコメントに
Next i
'ここにFile 書き込み処理を書く
Cells(8, 5) = "File 書き込み中"
frmTest.lblJyoukyou.Caption = "File 書き込み中"
For i = 7001 To 10000
'OSに処理を返す(画面描画を更新)
DoEvents
Cells(10, 5) = i
frmTest.txtJyoukyou.Value = i
'frmTest.Repaint '画面がちらつくのでコメントに
Next i
frmTest.lblJyoukyou.Caption = "処理終了しました"
Cells(8, 5) = "処理終了しました"
End Sub
フォーム
Option Explicit
Private Sub UserForm_Activate()
Call main
'処理終了のメッセージを表示
MsgBox "処理が終了しました。"
'フォームをアンロードする
Unload frmTest
End Sub
Private Sub btnClose_Click()
Dim CloseYesNo As Long
CloseYesNo = MsgBox("処理を中止しますか?", vbYesNo)
If CloseYesNo <> vbYes Then Exit Sub
Unload frmTest
End
End Sub
モーダレスVer.
Module1
Option Explicit
Sub Test()
frmTest.Show vbModeless 'モードレス
Call main 'ここにメイン処理を書くことができる
'処理終了のメッセージを表示
MsgBox "処理が終了しました。"
'フォームをアンロードする
Unload frmTest
End Sub
Sub main()
Dim i As Long
'ここにFile 読み込み処理を書く
Cells(8, 5) = "File 読み込み中"
frmTest.lblJyoukyou.Caption = "File 読み込み中"
For i = 1 To 3000
'OSに処理を返す(画面描画を更新)
DoEvents
Cells(10, 5) = i
frmTest.txtJyoukyou.Value = i
'frmTest.Repaint '画面がちらつくのでコメントに
Next i
'ここに計算処理実行処理を書く
Cells(8, 5) = "計算処理実行中"
frmTest.lblJyoukyou.Caption = "計算処理実行中"
For i = 3001 To 7000
'OSに処理を返す(画面描画を更新)
DoEvents
Cells(10, 5) = i
frmTest.txtJyoukyou.Value = i
'frmTest.Repaint '画面がちらつくのでコメントに
Next i
'ここにFile 書き込み処理を書く
Cells(8, 5) = "File 書き込み中"
frmTest.lblJyoukyou.Caption = "File 書き込み中"
For i = 7001 To 10000
'OSに処理を返す(画面描画を更新)
DoEvents
Cells(10, 5) = i
frmTest.txtJyoukyou.Value = i
'frmTest.Repaint '画面がちらつくのでコメントに
Next i
frmTest.lblJyoukyou.Caption = "処理終了しました"
Cells(8, 5) = "処理終了しました"
End Sub
フォーム
Option Explicit
Private Sub btnClose_Click()
Dim CloseYesNo As Long
CloseYesNo = MsgBox("処理を中止しますか?", vbYesNo)
If CloseYesNo <> vbYes Then Exit Sub
Unload frmTest
End
End Sub
プログラムコード
YouTube動画のソースコードです
YouTubeでは、処理があちこち飛ぶのでCall mainとせず
UserForm_Activateにメイン処理を直接書いています
モーダルVer.
Module1
Sub Test()
frmTest.Show vbModal 'モーダル(規定値)
End Sub
Sub main()
'ここにメイン処理を書いてもOK!
End Sub
フォーム
Private Sub btnClose_Click()
Dim CloseOkNo As Long
CloseOkNo = MsgBox("処理を中止しますか?", vbYesNo)
If CloseOkNo <> vbYes Then Exit Sub
'フォームをアンロードする
Unload frmTest
End
End Sub
Private Sub UserForm_Activate()
'メインの処理(orメインの処理を呼び出しても)
Dim i As Long
For i = 0 To 10000
DoEvents 'OSに処理を返す(画面描画を更新)
frmTest.TtxtJyoukyou.Text = i
Cells(8, 3) = i
Next i
'処理終了のメッセージを表示
MsgBox "処理が終了しました。"
'フォームをアンロードする
Unload frmTest
End Sub
モーダレスVer.
Module1
Sub Test()
frmTest.Show vbModeless 'モーダレス
Dim i As Long
'メインの処理(orメインの処理を呼び出しても)
For i = 1 To 10000
DoEvents
frmTest.TtxtJyoukyou.Text = i
Next i
'frmTest.lblOwari.Caption = "処理が終了しました"
MsgBox "処理が終了しました"
Unload frmTest
End Sub
Sub main()
'ここにメイン処理を書いてもOK!
End Sub
フォーム
Private Sub btnClose_Click()
Dim CloseYesNo As Long
CloseYesNo = MsgBox("処理を中止しますか?", vbYesNo)
If CloseYesNo <> vbYes Then Exit Sub
Unload frmTest
End
End Sub
続編のこちらもどうぞ!
プログレスバーで処理状況を表示します
コメント