For each xxx Next は使用対象のリソース(Sheet、セル、オブジェクトなど)がプログラミング時に確定できないときに使います(使うと便利です)。
リソースはコレクションと呼ばれる場合が一般的です。
具体例としては、
(1)Sheets ブック内に複数の(場合によっては規則的な名称を持っている)Sheetがあり、それらをすべて(あるいは選択して)処理する。
(2)Sheet内の複数のセルに対して処理する
(3)sheet内の複数の図形(Shape)に対して処理する
などです。
これらの処理は、どんな順で何を実行するか事前にわからない(事が多い)ので個人的には嫌いです。デバックもしにくいし、思ったようにマクロが実行しなかったときにも調査しにくいからです。
私の場合処理する対象を全て特定のシートに書き出して、それを再度読み込んで処理することが多いです。次に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
コレクション 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
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を使う例は思いつきませんでした。