t-hom’s diary

主にVBAネタを扱っているブログ…とも言えなくなってきたこの頃。

VBA フォームの更新が遅いときはDoEventsを挟んでみる。

今回はボタンを押すとフォームのテキストボックスをクリアするマクロを作成していたのだが、どうもテキストがクリアされるまでが遅く、ハマってしまった。前にも似たような内容でハマったことがあるので、いいかげん忘れないようにここに記しておく。

事象の再現方法

まず適当にフォームを用意し、テキストボックスとボタンを配置する。
f:id:t-hom:20151123040514p:plain

そして以下のようなコードを書く。

Private Sub CommandButton1_Click()
    TextBox1.Text = ""
    ThisWorkbook.Save
End Sub

実はこのコード、命令の順序はテキストのクリア→保存なのに、実行するとなぜか保存が終わってからテキストがクリアされる。

分かりにくければ保存の回数を増やしてみると、テキストのクリアが顕著に遅くなる。

Private Sub CommandButton1_Click()
    TextBox1.Text = ""
    For i = 1 To 5
        ThisWorkbook.Save
    Next
End Sub

※最初100回ループさせたところフリーズしてしまったので、5回くらいで良い。

原因

テキストクリアの命令を出すと、OSにフォームの再描画命令が出されるが、Excelは描画指示だけ出したらさっさと次の処理へ移ってしまう。
OSがフォームを書き直す前にワークブックの保存が実行され、そこでCPUが占有されるために描画が後回しになっている模様。

改善策

原因がわかってしまえば簡単なことで、テキストの更新命令の直後にDoEventsでOSに制御を渡してやれば良い。

Private Sub CommandButton1_Click()
    TextBox1.Text = ""
    DoEvents
    For i = 1 To 5
        ThisWorkbook.Save
    Next
End Sub

これで処理順は正しくテキストクリア→ブック保存となる。

今回はブックの保存で試したが、それ以外でもフォームテキスト更新後に重たい処理を実施する場合は同様の事象になる。

忘れずにDoEventsしておこう。

当ブログは、amazon.co.jpを宣伝しリンクすることによってサイトが紹介料を獲得できる手段を提供することを目的に設定されたアフィリエイト宣伝プログラムである、 Amazonアソシエイト・プログラムの参加者です。