With文の使い方
VBA でプログラミングをしていると、同じオブジェクトのプロパティやメソッドに何度もアクセスする場面が多く発生します。そんな時に便利なのがWith 文です。この記事では、With 文の基本から応用まで、具体例を交えて詳しく解説します。
With 文が必要となるシチュエーション
VBA で Excel のセルやワークシート、グラフなどを操作する際、同じオブジェクトに対して複数のプロパティを設定したり、メソッドを実行したりすることがよくあります。
例えば、あるセルに対して以下のような設定を行う場合を考えてみましょう。
Sub WithoutWithExample()
ActiveSheet.Range("A1").Value = "タイトル"
ActiveSheet.Range("A1").Font.Bold = True
ActiveSheet.Range("A1").Font.Size = 14
ActiveSheet.Range("A1").Font.Color = RGB(0, 0, 255)
ActiveSheet.Range("A1").Interior.Color = RGB(255, 255, 200)
ActiveSheet.Range("A1").HorizontalAlignment = xlCenter
End Sub
このコードでは、ActiveSheet.Range("A1")という同じオブジェクト参照が何度も繰り返されています。このような繰り返しは、以下のような問題を引き起こします。
- コードが冗長になり、読みにくくなる
- タイプミスのリスクが増える
- パフォーマンスの低下(オブジェクト参照の解決が毎回発生する)
- メンテナンス性の低下(対象セルを変更する際、すべての行を修正する必要がある)
こうした問題を解決するために、With 文が用意されています。
With 文とは
With 文は、同じオブジェクトに対する複数の操作をまとめて記述できる構文です。オブジェクト参照を一度だけ記述すれば、With…End With ブロック内ではピリオド(.)で始まる省略形を使用できます。
基本構文
With オブジェクト
.プロパティ1 = 値1
.プロパティ2 = 値2
.メソッド1
End With
Withの後に対象オブジェクトを指定し、ブロック内では.(ピリオド)から始めることで、そのオブジェクトのメンバーにアクセスできます。
With文を使用すると、オブジェクト参照の解決が最初の1回だけで済むため、処理速度が向上することがあります。ただし、大規模なデータ処理では他の最適化手法の方が効果的な場合もあります。
With 文の具体例
基本的な使用例
先ほどの例を With 文で書き換えてみましょう。
Sub WithExample()
With ActiveSheet.Range("A1")
.Value = "タイトル"
.Font.Bold = True
.Font.Size = 14
.Font.Color = RGB(0, 0, 255)
.Interior.Color = RGB(255, 255, 200)
.HorizontalAlignment = xlCenter
End With
End Sub
ActiveSheet.Range("A1")という参照が 1 回だけになり、コードがすっきりしました。ピリオドで始まる各行は、With 文で指定したオブジェクトに対する操作であることが一目でわかります。
ネストした With 文
With 文はネストすることもできます。例えば、セルとそのフォントオブジェクトをそれぞれ With 文で扱うことができます。
Sub NestedWithExample()
With ActiveSheet.Range("A1")
.Value = "重要なお知らせ"
.HorizontalAlignment = xlCenter
With .Font
.Name = "メイリオ"
.Size = 16
.Bold = True
.Color = RGB(255, 0, 0)
End With
With .Interior
.Color = RGB(255, 255, 200)
.Pattern = xlSolid
End With
End With
End Sub
ネストを使用することで、階層構造を持つオブジェクトの設定をより明確に記述できます。
With文を深くネストしすぎると、逆に可読性が低下する可能性があります。一般的には、2〜3階層程度に留めることが推奨されます。
複数セルへの一括設定
With 文は繰り返し処理と組み合わせることで、複数のセルに対する操作を効率的に記述できます。
Sub MultipleRangeWithExample()
Dim i As Long
'___ヘッダー行の設定
With ActiveSheet.Range("A1:E1")
.Value = Array("氏名", "年齢", "部署", "役職", "給与")
.Font.Bold = True
.Font.Size = 11
.Interior.Color = RGB(200, 200, 255)
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
End With
'___データ行の書式設定
For i = 2 To 10
With ActiveSheet.Rows(i)
.Font.Size = 10
.RowHeight = 20
'___交互に背景色を設定
If i Mod 2 = 0 Then
.Interior.Color = RGB(240, 240, 240)
End If
End With
Next i
End Sub
ワークシートオブジェクトとの組み合わせ
With 文は、ワークシート全体の設定にも便利です。
Sub WorksheetWithExample()
'___新しいワークシートを追加して設定
With Worksheets.Add
.Name = "月次レポート_" & Format(Date, "yyyymm")
'___ページ設定
With .PageSetup
.Orientation = xlLandscape
.PaperSize = xlPaperA4
.PrintTitleRows = "$1:$1"
.LeftMargin = Application.InchesToPoints(0.5)
.RightMargin = Application.InchesToPoints(0.5)
End With
'___タブの色を設定
.Tab.Color = RGB(100, 200, 100)
End With
End Sub
オブジェクト変数との併用
With 文はオブジェクト変数と組み合わせることで、より柔軟な使い方ができます。
Sub ObjectVariableWithExample()
Dim targetRange As Range
Dim ws As Worksheet
Set ws = ThisWorkbook.Worksheets("Sheet1")
Set targetRange = ws.Range("B2:D10")
'___範囲の書式設定
With targetRange
.NumberFormat = "#,##0"
.HorizontalAlignment = xlRight
'___枠線を設定
With .Borders
.LineStyle = xlContinuous
.Weight = xlThin
.Color = RGB(150, 150, 150)
End With
'___条件付き書式(10000以上を強調)
.FormatConditions.Delete
With .FormatConditions.Add(Type:=xlCellValue, _
Operator:=xlGreater, _
Formula1:="=10000")
.Font.Color = RGB(255, 0, 0)
.Font.Bold = True
End With
End With
End Sub
With 文の活用例
請求書テンプレートの作成
実務でよく使用される請求書テンプレートを作成する例です。
Sub CreateInvoiceTemplate()
Dim ws As Worksheet
Set ws = ActiveSheet
'___タイトル部分
With ws.Range("A1:F1")
.Merge
.Value = "請___求___書"
.Font.Size = 20
.Font.Bold = True
.HorizontalAlignment = xlCenter
.VerticalAlignment = xlCenter
.RowHeight = 40
End With
'___日付と請求番号
With ws.Range("A3")
.Value = "発行日:"
.Font.Bold = True
End With
With ws.Range("B3")
.Value = Date
.NumberFormat = "yyyy年mm月dd日"
End With
With ws.Range("D3")
.Value = "請求No:"
.Font.Bold = True
End With
'___明細ヘッダー
With ws.Range("A5:F5")
.Value = Array("No.", "品目", "単価", "数量", "金額", "備考")
.Font.Bold = True
.Interior.Color = RGB(200, 200, 255)
.HorizontalAlignment = xlCenter
With .Borders
.LineStyle = xlContinuous
.Weight = xlMedium
End With
End With
'___明細行(10行分)
With ws.Range("A6:F15")
.Borders.LineStyle = xlContinuous
.Borders.Weight = xlThin
.HorizontalAlignment = xlCenter
End With
'___合計欄
With ws.Range("E16")
.Value = "=SUM(E6:E15)"
.NumberFormat = "#,##0"
.Font.Bold = True
.Font.Size = 12
With .Borders(xlEdgeTop)
.LineStyle = xlDouble
.Weight = xlThick
End With
End With
End Sub
データ入力フォームの書式設定
ユーザー入力用のフォームエリアを整形する例です。
Sub FormatInputForm()
Dim ws As Worksheet
Set ws = ActiveSheet
'___フォームタイトル
With ws.Range("B2")
.Value = "社員情報登録フォーム"
.Font.Size = 16
.Font.Bold = True
.Font.Color = RGB(0, 0, 128)
End With
'___ラベル列の設定
Dim labels As Variant
labels = Array("社員番号:", "氏名:", "フリガナ:", "生年月日:", _
"部署:", "役職:", "入社日:", "メールアドレス:")
Dim i As Long
For i = 0 To UBound(labels)
With ws.Cells(4 + i, 2)
.Value = labels(i)
.Font.Bold = True
.HorizontalAlignment = xlRight
.Interior.Color = RGB(230, 230, 250)
End With
Next i
'___入力欄の設定
For i = 4 To 11
With ws.Cells(i, 3)
.Interior.Color = RGB(255, 255, 255)
.Borders.LineStyle = xlContinuous
.Borders.Weight = xlThin
.Borders.Color = RGB(150, 150, 150)
End With
Next i
'___列幅の調整
With ws.Columns("B")
.ColumnWidth = 15
End With
With ws.Columns("C")
.ColumnWidth = 30
End With
End Sub
グラフの詳細設定
グラフオブジェクトの複雑な設定も、With 文で読みやすく記述できます。
Sub FormatChartExample()
Dim ws As Worksheet
Dim cht As Chart
Set ws = ActiveSheet
Set cht = ws.ChartObjects(1).Chart
'___グラフ全体の設定
With cht
.ChartType = xlColumnClustered
.HasTitle = True
'___タイトルの設定
With .ChartTitle
.Text = "月別売上推移"
.Font.Size = 14
.Font.Bold = True
.Font.Color = RGB(0, 0, 128)
End With
'___軸の設定
With .Axes(xlCategory)
.HasTitle = True
.AxisTitle.Text = "月"
.TickLabels.Font.Size = 10
End With
With .Axes(xlValue)
.HasTitle = True
.AxisTitle.Text = "売上(円)"
.TickLabels.NumberFormat = "#,##0"
.MaximumScale = 1000000
End With
'___凡例の設定
With .Legend
.Position = xlLegendPositionBottom
.Font.Size = 9
End With
'___プロットエリアの設定
With .PlotArea
.Interior.Color = RGB(250, 250, 255)
End With
End With
End Sub
With 文使用時の注意点
パフォーマンスへの影響
With 文は一般的にパフォーマンス向上に寄与しますが、必ずしもすべてのケースで有効とは限りません。
Sub PerformanceExample()
Dim i As Long
'___With文を使わない場合(非推奨)
For i = 1 To 10000
ActiveSheet.Cells(i, 1).Value = i
Next i
'___With文を使う場合(推奨)
With ActiveSheet
For i = 1 To 10000
.Cells(i, 1).Value = i
Next i
End With
End Sub
大規模なデータ処理では、With文よりも配列を使用した一括処理の方が高速です。With文はコードの可読性向上が主な目的と考えましょう。
オブジェクトの明示的な参照
With 文のブロック内でも、必要に応じてオブジェクトを明示的に参照することができます。
Sub MixedReferenceExample()
With ActiveSheet
'___Withで指定したオブジェクトの参照
.Range("A1").Value = "タイトル"
'___別のオブジェクトの参照(明示的に記述)
Worksheets("Sheet2").Range("A1").Value = "別シート"
'___再びWithで指定したオブジェクトの参照
.Range("A2").Value = "サブタイトル"
End With
End Sub
Nothing チェック
オブジェクト変数を With 文で使用する際は、Nothing でないことを確認することが重要です。
Sub SafeWithExample()
Dim targetRange As Range
On Error Resume Next
Set targetRange = ActiveSheet.Range("NamedRange")
On Error GoTo 0
If Not targetRange Is Nothing Then
With targetRange
.Value = "データ"
.Font.Bold = True
End With
Else
MsgBox "指定された範囲が見つかりません。", vbExclamation
End If
End Sub
Nothingオブジェクトに対してWith文を実行すると、実行時エラーが発生します。必ずオブジェクトが有効であることを確認してください。
With 文のネストの限界
理論上、With 文のネストに深さの制限はありませんが、実用上は 2〜3 階層程度が推奨されます。
Sub NestedLimitExample()
'___適切なネスト(2階層)
With ActiveSheet.Range("A1")
With .Font
.Size = 12
.Bold = True
End With
End With
'___過度なネスト(非推奨)
With ActiveSheet
With .Range("A1")
With .Font
With .Characters(1, 3)
.Font.Color = RGB(255, 0, 0)
End With
End With
End With
End With
End Sub
まとめ
With 文は、VBA プログラミングにおいて以下のようなメリットをもたらします。
- コードの可読性向上 - 同じオブジェクトへの参照が明確になる
- タイプミスの削減 - オブジェクト参照を繰り返し入力する必要がない
- 保守性の向上 - 対象オブジェクトの変更が容易
- パフォーマンス改善 - オブジェクト参照の解決回数が減少(場合による)
一方で、以下の点に注意が必要です。
- 過度なネストは可読性を低下させる
- Nothing オブジェクトへの参照はエラーの原因となる
- 大規模データ処理では、他の最適化手法と組み合わせる
With 文を適切に活用することで、より読みやすく、保守しやすい VBA コードを書くことができます。特に、Excel の書式設定やオブジェクトのプロパティ設定など、同じオブジェクトに対する複数の操作を行う場合には、積極的に使用することをお勧めします。