質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

Q&A

解決済

2回答

3835閲覧

「お待ちください」表示用フォーム モーダルウィンドウの上にモードレスフォーム

neet_studier

総合スコア21

VBA

VBAはオブジェクト指向プログラミング言語のひとつで、マクロを作成によりExcelなどのOffice業務を自動化することができます。

0グッド

0クリップ

投稿2019/02/24 09:19

よろしくお願いいたします。

Excelでの質問です。
シート上にコマンドボタンを配置して、それをクリックすることで、様々な計算等の一連の処理を行なうように作りました。
そこまで来て、その処理に時間がかかるのが気になったため、「処理中です。手をふれないでそのまま待っててください」と表示させるためのフォーム(F_wait)を作り、処理開始から処理終了まで表示させることとしました。
処理の開始時に
F_wait.show
とだけ書くと、その時点で処理が中止されてしまうことがわかり、自分なりに調べたら

F_wait.show vbmodeless

と書けば、処理が中断せずに進行すると知り、そのようにして上手くいきました。

次に、同ファイルの別の場所での機能なのですが、あるモーダルフォームF1を表示させていて、そのF1上にあるコマンドボタンにも、
F1上のテキストボックスF1.txt1に入力されている値を使って、計算したり印刷したりシートのコピーを別ファイルとして保存したりといった、
一連の処理を作成しました。
この処理も処理に時間がかかるため、F_waitを表示させようとしたのですが、今度は
「モーダルフォームが表示されているときは、モードレスフォームを表示できません」とエラーが出て来てしまいます。

仕方がないからと、処理スタート時に、一旦

unload F1 F_wait.show modeless

とするわけにはいきません。
実行したい処理において、F1上のテキストボックスの値を参照したいからです。
とはいえ、F1の上にF_waitをモーダルでshowすると処理が止まってしまいます。

パッと思いつく対策は、F1上のテキストボックス群の諸値を変数に持ち、F1がunloadされた後でもその変数を用いて処理を続行する、ということなのですが、
しかし、この方法は、あまりスマートじゃない感じがするのと、
見た目的に、大きなF1がクリック後も表示されたままその中央あたりに小ぶりなF_waitが重なるように表示されることで、使用者にとってちゃんと何らかの処理がされているんだなという印象を持たせることができそうなので、そうしたいです。
デモデモダッテになりますが、だからといって、F_waitは、他の処理や今後の機能拡張でも使い回したいので、F_wait自体に処理のコードを書くもの避けたいです。

こういう状態でグダグダとしているのですが、何かいい方法はないでしょうか?
「お待ちください」表示フォームのことをまったく考えないでほとんどの処理を書いてしまったのがまずかったとは思ってるのですが、どうしたもんでしょう?

経験豊富な方はどうしておられるのか教えてください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答2

0

プログレスバー(お待ちください的なもの)は、
基本的に面倒なのでやりません。
※面倒な割に大して評価されませんし、
その上今回のようにメイン処理に悪影響を及ぼすことが多いので。

自分は、Application.Statusbar を使用します。
※最初と最後にクリア(Application.Statusbar = False)するようにします。

Excelが応答無しになってしまうと、もちろん経過は分かりませんが、
それはExcel自体の仕様で、何をやっても経過は分かりませんので、
使用者に、それでも動いているから、と教えます。

応答無しを回避する為には、DoEvents等を使います。
https://tsware.jp/tips/tips_114.htm

ご参考まで。

投稿2019/02/25 00:18

ExcelVBAer

総合スコア1175

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

neet_studier

2019/02/25 16:48

ご回答ありがとうございました。 ステータスバーのこと、参考になります。 ありがとうございました。
guest

0

ベストアンサー

モーダルのフォームからはモーダルしか呼び出せないというのは、処理に一貫性を持たせるための仕様なのでそれは尊重すべきだと思います。
モーダルで実行しているときは、他の処理は実行できない、ユーザーも処理が終わるまでは何もできないという仕様ということなので。

また、F_wait を他に処理にも使いまわしがきくようにしたいということなので、
F_Wait から他の処理(プロシージャ)を呼び出せるように設計すればどうでしょうか。
標準モジュールに記述したプロシージャなら、Application.Run
ユーザーフォームやシートモジュールに記述したプロシージャなら CallByName で呼び出せます。

F_waitのモジュール

vba

1Option Explicit 2Public ProcName As String 3Public obj As Object 4Public msg As String 5 6Private Sub UserForm_Activate() 7 Me.Label1.Caption = msg 8 If Not obj Is Nothing Then 9 CallByName obj, ProcName, VbMethod 10 Unload Me 11 ElseIf ProcName <> "" Then 12 Application.Run ProcName 13 Unload Me 14 End If 15End Sub

F1 のモジュール

vba

1Option Explicit 2 3Public Sub FormProc() 4 MsgBox "FormProc" 5End Sub 6 7Private Sub CommandButton1_Click() 8 Load F_Wait 9 With F_Wait 10 .ProcName = "FormProc" 11 Set .obj = Me 12 .msg = "FormProc を実行中です。しばらくお待ちください。" 13 .Show 14 End With 15End Sub 16 17Private Sub CommandButton2_Click() 18 Load F_Wait 19 With F_Wait 20 .ProcName = "ModuleProc" 21 .msg = "ModuleProc を実行中です。しばらくお待ちください。" 22 .Show 23 End With 24End Sub

標準モジュール

vba

1Option Explicit 2 3Public Sub ModuleProc() 4 MsgBox "ModuleProc" 5End Sub

改良案

上記のコードは、F_Wait の呼び出しがちょっと面倒です。呼び出しをメソッド(Subプロシージャ)にするとシンプルに呼び出せます。

F_waitのモジュール

vba

1Option Explicit 2Private sProcName As String 3Private sobj As Object 4 5Public Sub Start(ProcName As String, Optional msg As String, Optional obj As Object) 6 sProcName = ProcName 7 If Not obj Is Nothing Then Set sobj = obj 8 Me.Label1.Caption = msg 9 Me.Show vbModal 10End Sub 11 12Private Sub UserForm_Activate() 13 If Not sobj Is Nothing Then 14 CallByName sobj, sProcName, VbMethod 15 ElseIf sProcName <> "" Then 16 Application.Run sProcName 17 End If 18 Unload Me 19End Sub

F1 のモジュール

vba

1Private Sub CommandButton1_Click() 2 F_Wait.Start "FormProc", _ 3 "FormProc を実行中です。しばらくお待ちください。", _ 4 Me 5End Sub 6 7Private Sub CommandButton2_Click() 8 F_Wait.Start "ModuleProc", _ 9 "ModuleProc を実行中です。しばらくお待ちください。" 10End Sub

F_Wait.Start とメソッドを呼び出すことで、F_Wait は自動でLoadされます。あとは、引数で、プロシージャ名等を渡せばいいだけです。

投稿2019/02/24 12:42

編集2019/02/26 00:49
hatena19

総合スコア33715

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

neet_studier

2019/02/25 16:46

ご回答ありがとうございました。 まだ完全には理解できていませんが、私の希望にぴったりの方法だということはわかります。 何を我慢しなければいけないのか教えてもらうくらいの気でいたので、ここまで完璧な方法があるとは望外の喜びです。 とても勉強になりました。 ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問