For each xxx Next の使用

For each xxx Next は使用対象のリソース(Sheet、セル、オブジェクトなど)がプログラミング時に確定できないときに使います(使うと便利です)。

リソースはコレクションと呼ばれる場合が一般的です。

具体例としては、

(1)Sheets ブック内に複数の(場合によっては規則的な名称を持っている)Sheetがあり、それらをすべて(あるいは選択して)処理する。

(2)Sheet内の複数のセルに対して処理する

(3)sheet内の複数の図形(Shape)に対して処理する

などです。

これらの処理は、どんな順で何を実行するか事前にわからない(事が多い)ので個人的には嫌いです。デバックもしにくいし、思ったようにマクロが実行しなかったときにも調査しにくいからです。

私の場合処理する対象を全て特定のシートに書き出して、それを再度読み込んで処理することが多いです。次にSheet、セル、図形を対象とした処理の方法を紹介いたします。

 


 1.Sheetを対象とする場合

コレクション  Book内の全てのSheet

要素      各Sheet

(1)一般的な書き方

Sub LIST1()

Dim sh As Worksheet

For Each sh In Worksheets

'    ここに処理を書く

Next

 

End Sub

(2)特定のシート(複数)の全ての行を累積シートに追加する例

Sub LIST2()

Dim sh As Worksheet

Dim i, Max1, Max2 As Long

Max1 = Sheets("累積").Cells(Rows.Count, "A").End(xlUp).Row ’累積シートのクリア

 Sheets("累積").Range("A2:Z" & Max1).Clear

 Max2 = 2      ’累積シートの追加先行を求める

 For Each sh In Worksheets

 If Right(sh.Name, 2) = "売上" Then   ’シート名称の末尾が売上ならば

   Max1 = sh.Cells(Rows.Count, "A").End(xlUp).Row   ’その最大行数を求めて

   sh.Range("A2:Z" & Max1).Copy Sheets("累積").Range("A" & Max2)  ’累積シートに追加

   Max2 = Sheets("累積").Cells(Rows.Count, "A").End(xlUp).Row + 1   ’累積シートの追加先行を求める

End If

Next

 End Sub 

 2.セルを対象とする場合

コレクション  Sheet内の全てのセル

要素      各セル(通常セレクトされているセルかダブルクリックされたセル)

指定した行を別シートに移動する場合や、シートに表示しきれなかった情報を

別シートを選択して表示させる場合などに使うケースが考えられます。

(1)セレクトされたセルに対する一般的な例

Sub セル範囲1()

Dim rng1 As Range

Dim gyou As Long

For Each rng1 In Selection.Rows

  gyou = rng1.Row

 '   ここでその行に対する処理を記述

Next

End Sub

 

(2)ダブルクリックされた場合の例

マクロは通常のモジュールではなくワークシートに設定します

Private Sub Worksheet_SelectionChange(ByVal Target As Range)

Dim rng1 As Range

Dim gyou As Long

For Each rng1 In Selection.Rows

  gyou = rng1.Row

'  ここでその行に対する処理を記述

Next

End Sub 

 (3)フィルターで絞ったデータを処理する場合の例

 フィルターで絞っても、行をfor 2 to Max1 とかで集計すると、

 見えていない部分も集計してしまいます。

 見える部分だけ処理するには

 SpecialCells(xlCellTypeVisible).Rows という書き方をします。

 以下がその例です。

 

 Sub 集計test()

 Dim Max1, total As Long

 Dim R As Range  'for each の対象はRangeになります

 Dim chiiki As String

 chiiki = "東京"

 Range("A1").AutoFilter 2, chiiki    '2列目を地域の名称でフィルターをかけます

 Max1 = Cells(Rows.Count, "A").End(xlUp).Row

 If Max1 = 1 Then

   MsgBox "対象がありません"        '対象がないのに下記命令を実行するとエラーになります

   Exit Sub

 End If

 For Each R In Range("A2:C" & Max1).SpecialCells(xlCellTypeVisible).Rows

    total = total + Cells(R.Row, "C")   'レンジ名.Rowで(見えている対象の)行を意味します

 Next

 MsgBox total    '178が表示されます

  End Sub

 3.shape(図形)を対象とする場合

shapeを扱うためには、shapeの名称を知らなければなりません。

実はshapeを作成したとき、画面に表示されるShape名は本来のshape名ではありません。

『日本語に翻訳されたshape名』なのです。そしてその名称ではShapeをVBAで操作することはできない

のです。承知されている方は結構ですが、そうでない方は、shape名を表示するマクロを登録願います。

できればクイックアクセスツールバーに登録願います。

Sub 選択図形名表示()

Dim shp As Shape

For Each shp In Selection.ShapeRange

    MsgBox shp.Name

Next

 

End Sub

クイックアクセスツールバーへの登録方法は以下の通りです。 

①画面上部のクイックアクセスツールバーの下向き三角

 を押して『その他のコマンド』を選択

②基本的なコマンドのドロップダウンリストから『マクロ』

 を選択

③さきほどのマクロを選択して『追加』『OK』

 これで、クイックアクセスツールバーにマクロを起動

 するボタンが追加されます

ここで四角形の図形を追加して、shepe名を表示するマクロボタンを押してみました。

するとシート上はこのshapeの名前は『正方形/長方形 1』

になっていますが、メーセージボックスには

『Rectangle 1』と表示されています。こちらのほうが

正しいshape名です。

 

では日本語ではshapeを操作できないのかというとそうでは

なくて、図形を作成するとこにマクロを使用して

日本語名をつけてあげれば、日本語名で操作できます。

シート上のshape名称とマクロ上のshape名称を合致させるためには、shapeの生成を画面から行うのではなく、マクロ

で生成するのが早道です。

shapeの生成についてはここでは詳しく説明できませんが

日本語名でshapeを生成する例を紹介しておきます。

 

Sub 図形追加日本語()

    ActiveSheet.Shapes.AddShape(msoShapeRectangle, 300, 60, 72, 40).Name = "正方形/長方形 1"

    ActiveSheet.Shapes.AddTextbox(msoTextOrientationHorizontal, 400, 100, 80 _

        , 60).Name = "テキスト ボックス 1"

 

End Sub

(1)シート上のshapeを全て削除する

 Sub 図形削除all()

 Dim shp As Shape

 For Each shp In ActiveSheet.Shapes

          shp.Delete

 Next

 End Sub

 (2)シート上のshapeを種類指定で削除する

 Sub 図形削除英語()

 Dim shp As Shape

 For Each shp In ActiveSheet.Shapes

 If shp.Name Like "TextBox*" Then

         shp.Delete

 Else

   If shp.Name Like "Rectangle*" Then

          shp.Delete

   End If

 End If

  Next

   End Sub

(3)シート上の特定の範囲の図形を削除する

Sub 図形範囲1()

Dim Select_Range, Taisho_Range As Range

Dim shp As Shape

Set Taisho_Range = Range("D1:Z999")    ’削除する範囲

For Each shp In ActiveSheet.Shapes

Set Select_Range = Range(shp.TopLeftCell, shp.BottomRightCell) 

 If Not Intersect(Select_Range, Taisho_Range) Is Nothing Then ’削除する範囲と個別のshapeの範囲が重なっていれば

      shp.Delete

 End If

Next

 

End Sub

範囲の重複検出が二重否定になっていてわかりにくいですが、こんな書き方しか見つけられませんでした。

If Not を使わない書き方としては

If Intersect(Select_Range, Taisho_Range) Is Nothing = False Then も可能ですが

Nothing = False というのもいい加減わかりにくい表現です。調べた範囲ではNothingが必須のようです。

図形の操作は削除だけではなく、色や大きさ、テキストボックスの中の文字を編集するなどできますが

あえてFor eachを使う例は思いつきませんでした。