マクロ記録をすると、たとえば次のようなコードが記録されます。
With Selection.Interior .Pattern = xlSolid .PatternColorIndex = xlAutomatic .Color = 255 .TintAndShade = 0 .PatternTintAndShade = 0 End With
マクロの内容はともかく、今回はこの「With」の話です。Withって、いったい何でしょう?
Withはステートメントの一種です。マクロ記録で記録されるステートメントは、唯一このWithだけです。Withの働きは、われわれの日常会話を考えれば容易に理解できます。
たとえば、私の友人に「鈴木さん」という人がいたとします。私があなたに、この鈴木さんのことを紹介するとき、次のような言い方はしませんよね。
鈴木さんの出身は横浜で 鈴木さんの家族は4人で 鈴木さんの趣味はテニスで 鈴木さんの特技はギターなんですよ
こんな風に言ったら「鈴木さん、鈴木さんうるせぇよ」と怒られてしまうかもしれません。こんなとき、一般的にわれわれは、次のように言いますよね。
鈴木さんはね 出身は横浜で 家族は4人で 趣味はテニスで 特技はギター なんですよ
まず「鈴木さんはね」と宣言することで、これから話す内容は"鈴木さん"に関することであるという暗黙の取り決めをします。だから、次の「出身は横浜で」と言えば、これは"鈴木さん"の出身であると相手も理解してくれます。このように、何度も登場する主語を先に宣言しておき、その後の会話では主語を省略するときに使うのがWithステートメントです。上の会話をWithを使って表すと、次のようになります。
With 鈴木さん 出身は横浜で 家族は4人で 趣味はテニスで 特技はギター End With
最後の「End With」は、もう鈴木さんの話はここで終わりですよ、というような意味です。これを、もう少しVBAぽく書くと次のようになります。
With 鈴木さん の出身は横浜で の家族は4人で の趣味はテニスで の特技はギター End With
「の出身」というのは、「○○の出身」の「○○」つまり主語が省略されているという意味です。
では、Excelの操作で考えてみましょう。たとえば「セルA1に"tanaka"を代入して」「セルA1の背景色を赤くして」「セルA1の文字の色を白にして」「セルA1に文字列の表示形式を設定する」というマクロを作るとします。最初の、ウザい言い方をするなら
セルA1の値に"tanaka"を代入して セルA1の背景色を赤くして セルA1の文字の色を白にして セルA1に文字列の表示形式を設定する
となります。「セルA1、セルA1って何度もうるせぇよ」って感じです。実際にVBAのコードで書くと次のようになります。
Range("A1").Value = "tanaka" Range("A1").Interior.ColorIndex = 3 Range("A1").Font.ColorIndex = 2 Range("A1").NumberFormat = "@"
こうしたとき、Withを使って主語(操作の対象)を省略することができます。
セルA1のね 値に"tanaka"を代入して 背景色を赤くして 文字の色を白にして 文字列の表示形式を設定して くださいね
つまり、
With セルA1 の値に"tanaka"を代入して の背景色を赤くして の文字の色を白にして に文字列の表示形式を設定して End With
したがって
With Range("A1") .Value = "tanaka" .Interior.ColorIndex = 3 .Font.ColorIndex = 2 .NumberFormat = "@" End With
と書けるわけです。
ここでポイントは、With~End Withの間で主語(操作の対象)を省略したときは、それを明示するためにピリオドから書き始めるということです。言い換えると、ピリオドで始まっているオブジェクト式は、Withでくくったものが操作の対象になっているわけです。
誤解している人が多いのですが。WithとEnd Withの間では「必ず行頭がピリオドで始まる」わけではありません。WithとEnd Withの間にある「先頭がピリオドで始まっているオブジェクト式は対象(主語)が省略されている」ということです。したがって、次のような書き方もできます。
Sheets("Sheet1").Activate With Sheets("Sheet2") Range("A1") = .Range("B2") End With
上記のマクロを実行すると何が起きるか分かりますか。1行目で「Sheets("Sheet1").Activate」を行っていますので、アクティブシートは[Sheet1]になります。「Range("A1")」はワークシートを省略していますので、アクティブシートのセルA1という意味です。つまり、[Sheet1]のセルA1ですね。そこに「.Range("B2")」を代入しています。これはピリオドで始まっていますので、直前のWithでくくった[Sheet2]のセルB2を表します。
これが、Withステートメントの働きです。
最後に、少しだけVBAの仕組み的な話をします。意味が分からなければ、読み飛ばしてください(笑)。
Withステートメントがコンパイルされるとき、内部ではVBAがオブジェクト変数を用意して、そこにWithステートメントでくくったオブジェクトを格納します。ピリオドで始まる命令は、内部で確保したオブジェクト変数に対して行い、End Withが実行されると、確保したオブジェクト変数を開放します。
With Range("A1") .Value = 100 End With
というコードは、実際には次のようにコンパイルされます。
Dim xxx As Range Set xxx = Range("A1") xxx.Value = 100 Set xxx = Nothing
「xxx」は、VBAが内部で使用するオブジェクト変数の名前(のつもり)です。実際には、どんな名前が使われるか、われわれユーザーには分かりません。