フィルタで表示中の行だけ処理
フィルタ後に「見えている行だけ」を対象にする最短手は、SpecialCells(xlCellTypeVisible) を使うこと。AutoFilterの結果範囲から可視セルだけを取り出し、コピー・削除・集計・ループ処理に渡します。テーブル(ListObject)でも同様の考え方で安全に扱えます。
基本:フィルタ結果の“可視セルだけ”を取得して処理
Sub ProcessVisibleRows_Basic()
'見出しは A1、データは A2: 以降想定
Dim rng As Range, vis As Range
Set rng = Range("A1").CurrentRegion '表全体
rng.AutoFilter Field:=2, Criteria1:="営業A" '例:B列で絞り込み
On Error Resume Next
Set vis = rng.SpecialCells(xlCellTypeVisible) '可視セルだけ
On Error GoTo 0
If Not vis Is Nothing Then
'例:可視行だけ背景色を変更
vis.Offset(1).EntireRow.Interior.Color = RGB(255, 235, 156)
End If
End Sub
VB- ポイント:
- SpecialCells(xlCellTypeVisible): フィルタで隠れた行を除外し、見えているセル・行だけを対象にできます。
- CurrentRegion: 見出しセルから連続データ領域をまとめて取得して扱うと安全。
行単位で扱うときの定石(1列に限定→Rowで行番号)
Sub ProcessVisibleRows_RowWise()
Dim lo As Range, vis As Range, c As Range
Set lo = Range("A1").CurrentRegion
lo.AutoFilter Field:=3, Criteria1:=">=80" '例:C列が80以上
'列1(見出し列)に限定して可視セルを取得
On Error Resume Next
Set vis = lo.Columns(1).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not vis Is Nothing Then
For Each c In vis.Cells
'見出し行(A1)は除外
If c.Row > lo.Row Then
'例:可視行だけ合計列(E)へフラグを書き込む
Cells(c.Row, "E").Value = "対象"
End If
Next
End If
End Sub
VB- ポイント:
- 列を1列に絞る: 可視セル取得を列全体に対して行うと、行単位処理で列数分の重複が出る。1列に限定し、Rowで行番号を使うとスマート。
- 行番号の使い回し: 可視セル群から行番号を抽出して、他列の更新や削除にも応用できる。
可視行だけコピー・削除・集計
Sub CopyVisibleRows()
Dim tbl As Range, vis As Range
Set tbl = Range("A1").CurrentRegion
tbl.AutoFilter Field:=4, Criteria1:="=完了"
On Error Resume Next
Set vis = tbl.Offset(1).Resize(tbl.Rows.Count - 1).SpecialCells(xlCellTypeVisible) 'データ部のみ
On Error GoTo 0
If Not vis Is Nothing Then
vis.Copy Destination:=Range("H2")
End If
End Sub
Sub DeleteVisibleRows()
Dim tbl As Range, vis As Range
Set tbl = Range("A1").CurrentRegion
tbl.AutoFilter Field:=5, Criteria1:="=0" '例:金額=0
On Error Resume Next
Set vis = tbl.Offset(1).Resize(tbl.Rows.Count - 1).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not vis Is Nothing Then
vis.EntireRow.Delete
End If
End Sub
Sub SumVisibleRows()
Dim tbl As Range, vis As Range, s As Double, c As Range
Set tbl = Range("A1").CurrentRegion
tbl.AutoFilter Field:=2, Criteria1:="営業A"
On Error Resume Next
Set vis = tbl.Offset(1).Resize(tbl.Rows.Count - 1).Columns(5).SpecialCells(xlCellTypeVisible) '金額列(E)
On Error GoTo 0
If Not vis Is Nothing Then
For Each c In vis
s = s + Val(c.Value)
Next
Range("G2").Value = s
End If
End Sub
VB- ポイント:
- データ部に限定: 見出しを除いてデータ部だけを対象にするため Offset/Resize で1行下から範囲指定するのが定番。
- 可視列だけ集計: 金額列の可視セルだけを回して合計すれば、フィルタ条件に一致するデータの集計が簡単。
テーブル(ListObject)の可視行だけ処理
Sub ProcessVisibleRows_ListObject()
Dim lo As ListObject, vis As Range, r As Range
Set lo = ActiveSheet.ListObjects("売上テーブル")
'例:担当=営業Aで絞り込み(列名で指定)
lo.Range.AutoFilter Field:=lo.ListColumns("担当").Index, Criteria1:="営業A"
On Error Resume Next
Set vis = lo.DataBodyRange.SpecialCells(xlCellTypeVisible) 'データ部の可視セル
On Error GoTo 0
If Not vis Is Nothing Then
For Each r In vis.Areas
'各可視ブロックの行に対して処理
r.EntireRow.Interior.Color = RGB(198, 239, 206)
Next
End If
End Sub
VB- ポイント:
- DataBodyRange: テーブルのデータ部だけに限定して SpecialCells するのが安全。
- 列名で指定: ListColumns(“列名”).Index で列を特定すれば、列順が変わっても壊れにくい。
実務テンプレート:フィルタ状態の初期化→適用→可視行ループ
Sub VisibleRowsPipeline()
Dim ws As Worksheet: Set ws = ActiveSheet
Dim rg As Range, vis As Range, c As Range
Set rg = ws.Range("A1").CurrentRegion
'既存フィルタをクリア(安全運用)
If ws.FilterMode Then ws.ShowAllData
'新規条件でフィルタ
rg.AutoFilter Field:=3, Criteria1:=">=20", Operator:=xlAnd, Criteria2:="<30" '例:年齢20代
'見出し列に限定して可視セルを取得
On Error Resume Next
Set vis = rg.Columns(1).SpecialCells(xlCellTypeVisible)
On Error GoTo 0
If Not vis Is Nothing Then
For Each c In vis.Cells
If c.Row > rg.Row Then
'例:可視行の氏名(A列)をメッセージに出す
Debug.Print Cells(c.Row, "A").Value
End If
Next
End If
End Sub
VB- ポイント:
- ShowAllData: 既存の別条件フィルタが残っていると誤動作しやすい。開始前にクリアしてから適用が安定。
- 可視セル取得→Row活用: 列1に限定し Row を使って、行単位の処理に展開するのが定番。
実務の落とし穴と対策
- 可視セルが0件のときのエラー: SpecialCells は0件だとエラーになるため、On Error と Nothing チェックでガードする。
- 列複数での重複取得: 表全体で可視セルを取得すると列数分セルが返り、行単位処理で重複になる。1列に限定して Row を使う。
- テーブルと通常範囲の違い: テーブルは DataBodyRange を使うなど、対象の取り方が異なる。ListObjectのAPIを優先。
- 既存フィルタの干渉: FilterModeを確認し、必要に応じて ShowAllData で解除してから新条件を適用する。
