Debug.Printは出力のみ
コードの動作確認のために「Debug.Print」を使って、変数の内容などをイミディエイトウィンドウ出力することがあります。
ただ、「Debug.Print」メソッドは出力しっぱなしのため、マクロを動かすたびにイミディエイトウィンドウの最終行に追記される形で出力されるため、前回実行時との区切りがわかりにくくなります。前回実行時との区切りを出力するなどである程度分かりやすくすることもできますが面倒ではあります。
問題の根幹はイミディエイトウィンドウに前回実行時や手入力した内容が残ったままになっていることです。手で消してもいいですが、マクロを実行する度にイミディエイトウィンドウの内容をクリアして、きれいなログとして扱えるようにする方法を紹介します。
イミディエイトウィンドウに出力できる行数と外部出力方法
イミディエイトウィンドウには出力できる行数に限界があり、199行までしか保持されません。それ以降を出力するとその時点の先頭行の内容が消去されます。
もし、イミディエイトウィンドウに出力している内容を保持しておきたい場合は外部ファイルに出力するなどの方法を行う必要があります。
そのような場合は「VBAでログファイル出力を行う」をご参照ください。
クリア方法1.改行を埋め尽くす(その1)(おすすめ)
ほとんどの場合はこれで十分で安全なためこの方法をお勧めします。
ぱぱっ、と消したい場合は改行コードでイミディエイトを埋め尽くしてしまえば見た目上はクリアされたように見えます。体感では一瞬でクリアされます。実測では0.001秒とかそんな感じになると思います。
先に書いたとおり、イミディエイトウィンドウの限界行数は199行であるため、以下のコードは、String関数を使って改行コードCRLFを200個連結させた文字列を作り、それをイミディエイトウィンドウに出力しています。改行コードはCRLFを出力していますが、CRLFとCRとLFのいずれを出力してもイミディエイトウィンドウの内容をコピペするとCRLFが出力されます。
私自身、これを使ってます。
ちなみに関数名のCLSとは「CLear the Screen」の略で、GUIが無かった時代の古いPCのときからあったコマンドの名前で、それを借りてます。
1 2 3 |
Sub Cls1() Debug.Print String(200, vbCrLf) End Sub |
クリア方法2.改行を埋め尽くす(その2)
上のはString関数を使って改行コードを連結させていますが、String関数自体があまり使われることがない関数のため、文字列型のString型と名前が同じで分かりにくいと感じることも考えられます。というか、元は上のコードを実装していたのを人に見せたら「なにこれ?」と言われたので補足が以下です。
そこまで速度は求めないけど可読性の方を優先させたいという場合は、以下も1つ目と同様に改行コードで埋め尽くす方法ですがコードは分かりやすいと思います。ただ、ループで出力しているため体感速度では0.3秒ぐらい掛かります。
以下の関数はイミディエイトウィンドウの限界行数である200行分の改行を出力しています。
1 2 3 4 5 6 |
Sub Cls1() Dim i For i = 1 To 200 Debug.Print vbCrLf Next End Sub |
クリア方法3.内容を消去する方法(おすすめしません)
上記の2つの方法は改行コードで埋め尽くして、見た目上真っ白になってればOK、という方法です。
しかし、199行分のデータが出力された状態になっているため、イミディエイトウィンドウを全選択してテキストエディタなどに張り付けると空行を含めた199行が張り付いてしまいます。それが嫌な場合は物理的にイミディエイトウィンドウの内容を消去しなければなりません。
以下の方法はイミディエイトウィンドウを選択して、キーボードが押されたことを検知するキーイベントを使って、イミディエイトウィンドウの内容の全選択を行い、そのあとにDeleteキーのキーイベントで内容を消去する方法です。
キーイベントについての詳細は「VBAで疑似的にキーボード入力を行う(SendKeys)」をご参照ください。
イミディエイトウィンドウの指定に”イミディエイト”と”Immediate”のOr条件を入れているのは、日本語圏と英語圏の場合でCaptionプロパティの内容が異なるためです。個人的に英語圏でのExcelを使うことがあるためこのようにしていますが、日本で使うのであれば通常は”イミディエイト”だけでOKです。
しかし、この方法は問題が2つあるためお勧めしません。私自身も空行がどうしても邪魔な場合にしか使っていません。
問題の1つ目は、デバッグしながら動かすと、場合によってはコードエディタのプログラムの内容が全消去される恐れがあります。イミディエイトウィンドウにSetFocusメソッドでフォーカスを当てていますが、これをデバッグ中にソースコードがあるウィンドウに手で変えてから、そのあとの全選択+消去のキーイベントを実行するとソースが全部消えます。私はこれが嫌なので上で紹介した方法を使っています。
問題の2つ目は、Microsoft365であれば「Excelのオプション」→「トラストセンター」→「マクロの設定」→「VBAプロジェクトオブジェクトモデルへのアクセスを信頼する」にチェックが付いている必要があります。この設定はそこそこVBAの開発をやるような人しかチェックを付けないので、通常はチェックが付いていません。
チェックを付けるためにレジストリを変更するバッチを事前に実行する、ってのもありですが、「クリアするだけのためにそこまでやることか?」というのがあるので、以下のコードではレジストリの変更はしていません。
どうしてもレジストリを事前に操作したい場合は、
こっちでチェックON、
「reg add “HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Excel\Security” /v “AccessVBOM” /t REG_DWORD /d “1” /f」
こっちでチェックOFF
「reg add “HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Excel\Security” /v “AccessVBOM” /t REG_DWORD /d “0” /f」
になります。
コマンドの実行については「VBAでコマンドプロンプトの起動とコマンドの実行を行う」をご参照ください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
Sub Cls3() Dim wnd As Variant Dim bFlg As Boolean '// イミディエイトウィンドウ検出フラグ(True:検出、False:未検出) bFlg = False '// VBEのウィンドウをループ(イミディエイトウィンドウを検出するためのループ) For Each wnd In Application.VBE.Windows '// イミディエイトウィンドウの場合 If wnd.Caption = "イミディエイト" Or wnd.Caption = "Immediate" Then '// イミディエイトウィンドウを検出 bFlg = True '// 検出したのでここでループを抜ける Exit For End If Next '// イミディエイトウィンドウを検出できなかった場合 If bFlg = False Then '// 以降を処理せず抜ける Exit Sub End If '// 以下、イミディエイトウィンドウに対してキーイベントを実施 '// イミディエイトウィンドウにフォーカスを設定 wnd.SetFocus '// Ctrl + a(全選択) Application.SendKeys "^a", False '// Delete(消去) Application.SendKeys "{Del}", False End Sub |
使い方
使い方はただ上記関数を呼び出すだけです。
1 2 3 4 5 6 7 8 9 |
Sub ClsTest() Dim i For i = 0 To 200 Debug.Print i Next Call Cls1 End Sub |