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 プログラミングにおいて以下のようなメリットをもたらします。

  1. コードの可読性向上 - 同じオブジェクトへの参照が明確になる
  2. タイプミスの削減 - オブジェクト参照を繰り返し入力する必要がない
  3. 保守性の向上 - 対象オブジェクトの変更が容易
  4. パフォーマンス改善 - オブジェクト参照の解決回数が減少(場合による)

一方で、以下の点に注意が必要です。

  • 過度なネストは可読性を低下させる
  • Nothing オブジェクトへの参照はエラーの原因となる
  • 大規模データ処理では、他の最適化手法と組み合わせる

With 文を適切に活用することで、より読みやすく、保守しやすい VBA コードを書くことができます。特に、Excel の書式設定やオブジェクトのプロパティ設定など、同じオブジェクトに対する複数の操作を行う場合には、積極的に使用することをお勧めします。

#VBA #With文 #基本構文 #コーディング