Excel (VBA)

Excel VBAに関するフォーラムです。
  • 解決済みのトピックにはコメントできません。
このトピックは解決済みです。
質問

 
(Windows 11 Pro : Excel 2021)
二重ループのコードの書き方について
投稿日時: 25/02/19 19:59:23
投稿者: シナモンジンジャー

定型封筒の宛名の連続印刷のリストを下のように作りました。宛名のデータベースは1件ずつ横1行になっており、それをVLOOKUPで検索して封筒には差出先住所と宛先を横書き7行に印字されるようになっています。
宛名には住所1、住所2、住所3、入居建物名、会社名、担当者名、内容物などたくさんあるので、データベースの宛名の列数もその分だけあります。封筒の宛名人の行だけは様や御中などを選択して入れる必要があるため、特定の行で固定しています。そうすると、住所1と宛名人だけの最初の行と宛名人の行の2行で差し出す宛先もあれば、宛先7行とも目いっぱい使う宛先もあることから住所2から会社名の行の間に空行が出てバランスが悪くなることがあります。そのため、1件印刷に入るたびに空行を検索して非表示にしたあと印刷するようにしたいのです。
下のマクロのリストは、印刷開始番号から印刷終了番号までループで印刷を繰り返すものが第1のループで、その中に32列目の検索結果で空行を検索してその行を非表示にするループが第2のループです。
試してみたら、1件目の封筒だけは空行非表示になりますが、2件目以降は空行非表示のループを飛ばして第1ループの終了まで飛んでしまい、空行が入ったまま印刷されてしまいます。どこを直せばよいか分かりません。二重ループの書き方に詳しい方リストの拙いところを教えてください。よろしくお願いします。
 
Sub 長3封筒宛名選択印刷()
 
 Dim Pz, StNo,EndNo As Integer
  StNo = Range("N4")
  EndNo = Range("V4")
  Dim i As Long
  Dim LastRow As Long
 
  Sheets("長3封筒").Select
  ActiveSheet.PageSetup.PrintArea = "$B$3:$L$33"
          
  For Pz = StNo To EndNo        ’第1ループ開始
        Range("V1") = Pz
        If Pz = StNo Then
        LastRow Cells(Rows.Count,32).End(xlUp).Row    '基準列32列(AF)
    '行をループ  最終から13行目まで
        For i =LastRow To 13 Step -1        ’第2ループ開始(空行非表示)
        If Cells(i,32) = "" Then
        Rows(i).Hidden = True '行を非表示
        End If
        Next i                     '第2ループ終了
 Application.Dialogs(xlDialogPrint).Show
 Else
 ActiveSheet.PrintOut
 End If
    Rows("13:19").Select
    Selection.RowHeight = 23.25
 Next Pz                              '第1ループ終了
 
    Rows("13:19").Select                '印刷後すべての行を表示する
    Selection.RowHeight = 23.25
  ActiveSheet.PageSetup.PrintArea = False
 Range("C12").Select
 End Sub

回答
投稿日時: 25/02/19 23:37:52
投稿者: simple

提示されたコードを内容は変えずに、インデントをつけてみました。
(手作業ではなく、実行したのはツールですが)
ご覧になって、ヒントになることがあれば幸いです。
 

Sub 長3封筒宛名選択印刷()
    Dim Pz, StNo, EndNo As Integer
    StNo = Range("N4")
    EndNo = Range("V4")
    
    Dim i       As Long
    Dim LastRow As Long
    Sheets("長3封筒").Select
    ActiveSheet.PageSetup.PrintArea = "$B$3:$L$33"

    For Pz = StNo To EndNo        '第1ループ開始
        Range("V1") = Pz
        If Pz = StNo Then
            LastRow Cells(Rows.Count, 32).End(xlUp).Row  '基準列32列(AF)
            '行をループ  最終から13行目まで
            For i = LastRow To 13 Step -1       '第2ループ開始(空行非表示)
                If Cells(i, 32) = "" Then
                    Rows(i).Hidden = True    '行を非表示
                End If
            Next i                     '第2ループ終了
            Application.Dialogs(xlDialogPrint).Show
        Else
            ActiveSheet.PrintOut
        End If
        Rows("13:19").Select
        Selection.RowHeight = 23.25
    Next Pz                              '第1ループ終了

    Rows("13:19").Select                '印刷後すべての行を表示する
    Selection.RowHeight = 23.25
    ActiveSheet.PageSetup.PrintArea = False
    Range("C12").Select
End Sub

細かい点についてコメントすることはありますが、
それはさておき、取り急ぎコメントしておきます。

投稿日時: 25/02/20 07:59:40
投稿者: シナモンジンジャー

ありがとうございます。
ループを追加したり、元の行高に戻してループに返ったりしてコードを追加するのでインデントそろえはいい加減になってしまいます。申し訳ありません。

回答
投稿日時: 25/02/20 08:57:43
投稿者: simple

いえいえ申し訳ないことはありません。
ご自分に返ってきているだけの話なので、こちらは一向に構いません。
  
インデントをつけるとコードの論理構造が分かりやすくなるのでは?という話です。
インデントを付けたコードにご覧になって、何か気づいたことはありませんか?
ループの初回だけ実行したいことは何ですか? コードはそのようになっていますか?
  
# 回答を待っておられるようですけど、打ち返すべきボールはそちらにあると思っています。

回答
投稿日時: 25/02/20 09:15:15
投稿者: MMYS

シナモンジンジャー さんの引用:

試してみたら、1件目の封筒だけは空行非表示になりますが、2件目以降は空行非表示のループを飛ばして第1ループの終了まで飛んでしまい、

Pz  処理する行
StNo 最初の行
 
ですよね。で、コードを確認すると、下記のように書かれております。第1ループ直後に、1件目と2件目以降で処理の分けてますので、当然の動きです。
 
    For Pz = StNo To EndNo '第1ループ開始
        Range("V1") = Pz
        If Pz = StNo Then
        <略>
      Else
       ActiveSheet.PrintOut
      End If
 
 
なお、デバックですが、いきなり、2重ループのコードを書いてはいけません。まず、Pz を指定したら、そのPzで指定した1件が確実に動作するコードを作成します。Pzを書き換えて、指定した行確実に動作するコードを完成させます。ループ化して複数対応は、その後です。
 
指定した1件のみ印刷が確実に動作するコードを完成したら、この時点でPzさえ指定すればよいので。あとは、第1ループを追加。Pzの値をループで変化させ複数印刷機能を追加します。
 
ステップ1。PZの値で、1件が確実に動作するコードを作成・デバックする。
'    For Pz = StNo To EndNo        '第1ループ開始
    Pz = 18 '←Pzを直接指定してデバック
        Range("V1") = Pz
       '< Pzで指定した1件を印刷コードを作成する>
' Next Pz                         '第1ループ終了

ステップ2。PZの値をループに変更する。
    For Pz = StNo To EndNo        '第1ループ開始
'    Pz = 18 '←Pzを直接指定してデバック
        Range("V1") = Pz
       '< Pzで指定した1件を印刷コードを作成する>
    Next Pz                       '第1ループ終了

投稿日時: 25/02/20 16:27:42
投稿者: シナモンジンジャー

なぜ、直接、値を当てはめた後わざわざデバッグするのでしょうか。
 
 

引用:
Pz = 18 '←Pzを直接指定してデバック
        Range("V1") = Pz
       '< Pzで指定した1件を印刷コードを作成する>

 
この行の役割を教えてください。これまで、こういうふうに作ってこなくて、空行非表示の作業をしない場合はそれぞれの宛名をVLOOKUPで検索代入するだけで普通に動作していたのでわからないので教えてください。

回答
投稿日時: 25/02/20 16:51:46
投稿者: 半平太

ちょっと教えてください。
 
>32列目の検索結果で空行を検索してその行を非表示にするループが第2のループです。
 
その列の空白は、本当の空白ですか(所謂未入力セル?)
それとも数式で出した空白文字ですか?(通常は→ "" )
 
その判定に使われる範囲は「AF13:AF19」で確定的なんでしょうか?
また、AF13は含めても意味がない気がするんですが・・

投稿日時: 25/02/20 20:02:35
投稿者: シナモンジンジャー

封筒の各行にVLOOKUPで番号検索された値が代入されていますが、AF列(封筒印刷範囲のそと)には、その値(つまりデータベースで空白になっているセル値)は""を返すようにしてあります。その空白セルを検索してその行を非表示にしています。それで、それぞれの宛名データが代入されるたびにAF13からAF17までは""を返されたセルが変わってきます。

回答
投稿日時: 25/02/20 22:36:49
投稿者: 半平太

>AF13からAF17までは""を返されたセルが変わってきます。
そうですか・・、
13行目が非表示になることは現実的に無いと思ったのですが、
早とちりでしたか。
 
さて、 第2ループを開始する条件が If Pz = StNo となっていますが、
それだと、1回目だけ非表示処理をすると言う意味なので、
目的に合っていないと思います。
 
条件は、「AF13:AF19 に空白が有ったら」となるべきなので
 
>If Pz = StNo Then
 ↓
 If Application.CountIf(Range("AF13:AF19"), "") Then 'としたらどうですか?
 若しくは
 If Application.CountIf(Range("AF13:AF17"), "") Then
                   ↑
                  なのかなぁ・・
            (ちょっとこっちでは何が正しいのか分からないです)
 
※あと、LastRowを取得する意味もちょっと分からないです。
 チェック範囲は AF13:AF19(or AF13:AF17) だと思うので、
  その範囲に限定した方が簡明だと思います。
 また、LastRowは毎回同じハズなので、
  ループの中に入れるのは無駄ではないか、と言う気がします。
 まっ、以上の点は今回スルーしますけど。

投稿日時: 25/02/21 07:45:29
投稿者: シナモンジンジャー

Pz は $V$1の宛先の印刷番号を代入する変数で 
i は $AF列の複数宛名行の有無を代入する変数です。
これを一緒にループすることはできないのですが。

回答
投稿日時: 25/02/21 13:03:27
投稿者: simple

初回と二回目以降で区別するのは、出力の仕方だけではないんですか?

       If Pz = StNo Then
            Application.Dialogs(xlDialogPrint).Show
       Else
            ActiveSheet.PrintOut
       End If
そのほかの共通の処理は、この中には入れる必要がない、入れてはダメということです。
具体的には、その5行のコードの前で、空白処理対応をすればよいと思います。
 
なお、論理的な内容にするには正確なインデントをつけることが助けになるはずです。
多重ループや、条件判断が入れ子になっているような場合は、特に重要です。
そういう時だからこそ、インデントをしっかりつけることが大切だと思います。
それを曖昧にしているのは、ご自分にハンディキャップを課しているようなものだと思います。
 
ちなみに、"リスト"じゃなく"コード"と呼ぶのが普通では?

投稿日時: 25/02/21 20:52:21
投稿者: シナモンジンジャー

私のイメージしている二重ループは、第1のループで宛名一覧表(データベース)の中から、印刷開始番号をPzに代入して印刷開始番号1の宛名(宛名1〜会社名又は担当者名まで)を封筒の各行のVLOOKUPで表示させます。
その状態で第2のループに入り、封筒の各行のうち値が返された行には目印の「1」を、何も返さなかった行には「""」をAF列に反映させておいて、AF列の最下行(1048576行目)から上方へ13行目までを検索して「""」を返された行は非表示にしていき、完了したら第2のループは終了します。
そして、第1ル−プの作業であるプリントアウトをしたあと、Pzの次値を$V$1に代入して、印刷開始番号の次号の宛名(宛名1〜会社名又は担当者名まで)を封筒の各行のVLOOKUPで表示させておいて、同じようにループ2に進み、空行を検索して非表示にした後、プリントアウトに入るというイメージです。
1件ごとに宛名が2行だけだったりそれ以上〜7行だったりするのでプリントアウトが1件終わるたびに全行表示に戻す作業も入れてあります。
1件目の宛名印刷ではちゃんと空行を検索して非表示作業をしてプリントするのに、次の印刷番号を$V$1に代入したあとは第2ループを飛ばしてしまい、空行非表示の作業をせず第1ループの作業(次のプリントアウト)だけをするので、なぜそうなるのか分からないのです。
毎回の第1ループのなかで毎回第2ループの作業をさせて、第1ループに戻すというコード進行の書き方を具体的に教えてください。自己流でなんとかシンプルなマクロの書き方を覚えたので、今回の二重ループは難関です。よろしくお願いします。

回答
投稿日時: 25/02/21 21:26:15
投稿者: simple

引用:
1件目の宛名印刷ではちゃんと空行を検索して非表示作業をしてプリントするのに、次の印刷番号を$V$1に代入したあとは第2ループを飛ばしてしまい、空行非表示の作業をせず第1ループの作業(次のプリントアウト)だけをするので、なぜそうなるのか分からないのです。

以下の抜粋は、あなたのコードそのものです。
        If Pz = StNo Then
            LastRow Cells(Rows.Count, 32).End(xlUp).Row  '基準列32列(AF)
            '行をループ  最終から13行目まで
            For i = LastRow To 13 Step -1       '第2ループ開始(空行非表示)
                If Cells(i, 32) = "" Then
                    Rows(i).Hidden = True    '行を非表示
                End If
            Next i                     '第2ループ終了
            Application.Dialogs(xlDialogPrint).Show
        Else
            ActiveSheet.PrintOut   
        End If
Pz = StNoのときは、空行非表示の処理をしていますが、
2つめ以降のデータのときは、Pz = StNo ではありませんから、Else以下が実行され
            ActiveSheet.PrintOut
という1行が実行するだけですから、空行非表示の処理はされませんよね。
 
ご自分でステップ実行してどの行が実行されていくか、目で具体的に確認されたらどうですか?
 
=====================
どのようにしたらよいかも既に
投稿日時: 25/02/21 13:03:27
で書いていますよ。
 
例えば、こんな風に書いたらどうですか?
 
Sub 長3封筒宛名選択印刷()
    Dim Pz As Long, StNo As Long, EndNo As Long '変数の型の宣言はひとつひとつに必要
    StNo = Range("N4")      '"長3封筒"と違うシートなら、シート名を特定する必要?
    EndNo = Range("V4")

    Dim i       As Long
    Dim LastRow As Long
    
    Sheets("長3封筒").Select
    ActiveSheet.PageSetup.PrintArea = "$B$3:$L$33"
    LastRow = Cells(Rows.Count, "AF").End(xlUp).Row     '基準列

    For Pz = StNo To EndNo
        Range("V1") = Pz                 '基準データセルの更新。
                                         'これによって他のセルが再計算される
        For i = LastRow To 13 Step -1    '空行非表示処理
            If Cells(i, "AF") = "" Then
                Rows(i).Hidden = True
            End If
        Next i
        '印刷処理
        If Pz = StNo Then
            Application.Dialogs(xlDialogPrint).Show
        Else
            ActiveSheet.PrintOut
        End If
        Rows("13:19").RowHeight = 23.25  '全行表示に
    Next Pz

    ActiveSheet.PageSetup.PrintArea = False
    Range("C12").Select
End Sub

実際のデータもこちらには無いので、空行非表示の処理は正確に動作するかは保証の限りではありませんが、質問には応えているはずです。

回答
投稿日時: 25/02/21 23:21:21
投稿者: MMYS

シナモンジンジャー さんの引用:
2件目以降は空行非表示のループを飛ばして第1ループの終了まで飛んでしまい、空行が入ったまま印刷されてしまいます。どこを直せばよいか分かりません。二重ループの書き方に詳しい方リストの拙いところを教えてください。

まず、 どこを直せばよいか分かりません。とのことですが、 シナモンジンジャーさん自身は、なぜ、そのような動きになるか、どのように調べてましたか。
 
頭の中の処理手順を実際のコードにするのが、コーディングですが、バグ原因は、
・頭の中の処理手順が実際のコードに反映されてない。
・そもそもの頭の中の処理手順が間違っている。
のどちらかが大半です。
 
プログラムが動かないときは
・頭の中では、○○ と動くはず。
・実際の動作は、△△ と動く。
ですよね。
 
さて、シナモンジンジャーさんが頭の中で考えた処理手順通りに、コードは実行されてますか。また、それをどのように確認されましたか。
 
 
シナモンジンジャー さんの引用:

1件目の宛名印刷ではちゃんと空行を検索して非表示作業をしてプリントするのに、次の印刷番号を$V$1に代入したあとは第2ループを飛ばしてしまい、空行非表示の作業をせず第1ループの作業(次のプリントアウト)だけをするので、なぜそうなるのか分からないのです。

結論から言いましょう。第1ループの直後に判定してます。
コードを、アルゴリズムに直すと、次の通り。
 
 初期設定
 第1ループ開始
  判定
   第2ループ開始
    行非表示
   第2ループ終了
  行再表示
 第1ループ終了
 後処理
 
 
第2ループに入る前に、判定しており、しかも、開始行の時のみ、第2ループに入るように、判定コードを書いてます。1件目は処理されるが、2件目以降は処理されません
 
そのように動くように、シナモンジンジャー さんがコードを記述したのだから。
 
 
シナモンジンジャー さんの引用:
なぜ、直接、値を当てはめた後わざわざデバッグするのでしょうか。

その説明をする前に、シナモンジンジャーさん自身は、どのようにデバックされてますか。
 
たとえば、今回のケースだと、第1ループの回数が、10回ループだとすると、第2ループも10回実行される。これがシナモンジンジャーさんが考えたアルゴリズムですよね。
 
で、第2ループが10回実行されることを確認されましたか。
たとえば、
 
        LastRow Cells(Rows.Count,32).End(xlUp).Row '基準列32列(AF)
        '行をループ  最終から13行目まで
        Msgbox Pz
        For i =LastRow To 13 Step -1 ’第2ループ開始(空行非表示)
 
と第2ループ開始直前に 確認コード(Msgbox)を記述。これで、シナモンジンジャーさんの考えでは、Msgboxにより、 Pz値 が10回表示されるはずです。
もし、1回しか実行されてないと気づけば、何故だ。となり、第2ループ直前に、誤った判定コードがあるのでは。と推測。そのあたりをバク原因として探すわけです。
 
なお、ベテランプログラマでも、一発で動くことは、ありません。動かないのが当たり前。つまり、デバック方法を習得していなとコードを書くことはできません。
 

回答
投稿日時: 25/02/22 09:02:43
投稿者: MMYS

補足しますが、シナモンジンジャー さんは、ネストを理解・意識してますか。ネストを理解してないと、
・IF文でインデント下げをする理由。
・多重ループ
・インデントでネストを表現 する
を理解できません。
 
 
二重ループが分からないのではなく
 「入れ子」
を理解してないのでは。と推測しますが。
 
 

投稿日時: 25/02/22 13:05:49
投稿者: シナモンジンジャー

何回も丁寧なご説明ありがとうございます。教えていただいたコードを見てみると$V$1の値をpZに代入してすぐに空白処理に入り、そのあと連続印刷作業の第1ループに入っているように見えました。
書かれている通り

引用:
 初期設定
 第1ループ開始
  判定
   第2ループ開始
    行非表示
   第2ループ終了
  行再表示
 第1ループ終了
 後処理

という順番にコードを並べたつもりでしたが、第1ループが開始してまず空白行判定・処理からなんですね。正直ネストの受発のことはよくわかりませんでした。もし、うまく稼働したら、もう1枚の角2封筒連続印刷のシートのコードにも空白処理の第2ループを追加したいと思っています。
教えていただいたコードを職場のパソコンで試してみます。私の職場は、USB使用ができない(ほぼ禁止)、業務用の登録されたメアド以外へのメール送受信も不接続なので、自宅パソコンでいただいたコードを試すことができません。質問に出したコードは職場でコードをプリントアウトして持ち帰ってきてmougのフォーラムに再現したところです。
simple様には本当に丁寧に教えてくださったので、多分大丈夫なような気がするのですが、試していないのですぐにお返事ができなくて申し訳ありません。結果をしばらくお待ちいただけますでしょうか。

回答
投稿日時: 25/02/22 13:59:18
投稿者: Suzu

自分で考え書いたコードを動かしてみたけど、思い通りの結果が得られない。
これはよくある話です。
 
基本、問題が起きるのは、想定していたフロー とは違うフローでプログラムが進むから。
想定していたフローにならないのは、
 ・条件分岐を入れる位置がそもそも違う
 ・条件分岐の式が違う
のどちらかである事が多く、プログラムがどんなフローで進んでいるかを把握しなくては
どの部分に問題があるのかを把握できません。
 
その間違いを探し修正する必要があり、その修正作業をデバッグと言います。
 
質問者さんは、そのデバックの方法を知らないのではないですか?
 
デバックの為には、どの条件分岐でどんな判定がされるかを目に見える形にして
デバック者が コードフローを把握する必要があります。
 
その為にはいろんな方法があります。
・コードの中に MSGBOX を入れ 今どの部分のコードが進んでいるのかを目に見える様にする
・ブレークポイントを設置し、あるコード位置に来たらコードが止まる様にし 変数の内容等を確認する
・ステップ実行を行い、実際に どんな 順番でコードが進んでいるか 1行づつ追っていく
 
質問者さんは、それらを ひとつでもご存じですか?
それを自分でできないなら、コードを作るのは、とても難しくなります。
 
ExcelVBA入門 自宅でプログラミング
 デバッグの意味とデバッグ手法
https://www.239-programing.com/excel-vba/basic/basic020.html
 
を参考にし、デバックの方法を学び習得してください。
 
デバックを行う様になっていくと、
多層的な条件分岐についても見るはずです。
 
今のコードが実行されるには、どんな条件分岐を通ってきたのかを把握する必要があります。
 
例えば
 If 一番目の判定 Then
  If 二番目の判定 Then
    Else
      If 三番目の判定 Then
      End If
  End If
Else
  〜〜
End If
 
こんな感じにインデントをつけておけば
 三番目の判定の段階では
  一番目 の 判定 が True、二番目の判定 が Else の場合と 判りやすくありませんか?
それが、インデントがある事で分かり易くなります。
 
デバックを知らない人にしてみたら、インデントの必要性が判りませんよね。
どんな条件分岐を通って そこに至ったのかを考えた事無いですから。
自分でコードの動作を追うと、インデントがある事のメリット理解できる様になります。
 
まずは、デバックのしかたについて身につけましょう。

投稿日時: 25/02/22 18:29:48
投稿者: シナモンジンジャー

Suzuさまには、基本的なコード進行の方法を指摘していただきありがとうございます。私は、VBAの標準モジュールの画面を開いて、F8キークリックで1行ずつ確かめながらコード進行を見ているのですが、第1ループから第2ループに入って1通目を印刷したので、今度は次の宛名番号が代入されたところからF8キークリックで進行していくと第2ループを飛ばしてしまう状態はなぜそうなるかが分からなくてsimpleさまに教えていただいたところです。

回答
投稿日時: 25/02/23 10:10:00
投稿者: simple

シナモンジンジャー さんの引用:
F8キークリックで1行ずつ確かめながらコード進行を見ているのですが、第1ループから第2ループに入って1通目を印刷したので、今度は次の宛名番号が代入されたところからF8キークリックで進行していくと第2ループを飛ばしてしまう状態はなぜそうなるかが分からなくて・・・

教えてもらったというか、普通はステップ実行すれば間違いに気づくはずなんですが。
二重ループがどうこうというよりも、
 If 条件 Then
     処理1
 Else 
     処理2
 End If
という条件分岐がわかっていらっしゃらない ということですかね。
条件を満たしたときは、処理1が実行され、満たさないときは、処理2が実行されるということが
理解されていなかったということでしょうか。
 
念のため、違いがわかりますか?
(1)当初のコード
    For Pz = StNo To EndNo
        Range("V1") = Pz '基準データセルの更新。
                           'これによって他のセルが再計算される
        '印刷処理
        If Pz = StNo Then

            For i = LastRow To 13 Step -1 '空行非表示処理
                If Cells(i, "AF") = "" Then
                    Rows(i).Hidden = True
                End If
            Next i

            Application.Dialogs(xlDialogPrint).Show
        Else
            ActiveSheet.PrintOut
        End If

        Rows("13:19").RowHeight = 23.25 '全行表示に
    Next Pz
(2)修正案
    For Pz = StNo To EndNo
        Range("V1") = Pz '基準データセルの更新。
                           'これによって他のセルが再計算される
        For i = LastRow To 13 Step -1 '空行非表示処理
            If Cells(i, "AF") = "" Then
                Rows(i).Hidden = True
            End If
        Next i

        '印刷処理
        If Pz = StNo Then
            Application.Dialogs(xlDialogPrint).Show
        Else
            ActiveSheet.PrintOut
        End If

        Rows("13:19").RowHeight = 23.25 '全行表示に
    Next Pz

投稿日時: 25/02/23 13:19:29
投稿者: シナモンジンジャー

オレンジと青の文字色で分けてくださって、私の書いたコードでは最初のIF〜End IFの条件文の中に違う作業のループが挟まっているのが分かりました。
お示しいただいたコードでは、Pzが代入されたら、まず空白行処理に入り、終了したら印刷に入り、もとの行高に戻したあと次のPzに進むというのが大変よくわかります。
  For〜 Next の中に 第2ループの For〜 Nextの入れ方とIF〜End IFの分岐の書き方の順番が頭の中で整理てされよくわかりました。ありがとうございました。