和風スパゲティのレシピ

日本語でコーディングするExcelVBA

ワークシートを指定する方法7選

ExcelVBAのマクロにおいて、処理の主役はもちろんセルですが、
このセルを処理するためには、どのシートのセルなのかを指定する必要があります。

この「ワークシートの指定方法」はいろいろなやり方があり、
どれがいいというわけではなく、一長一短があります。


ワークシートの指定は、ExcelVBAのコードおいて素地となる重要な要素ですので、
上手く書けるようになると、マクロが書きやすく、そして読みやすくなります。


「基本的だけど効果の高い方法」に厳選して解説していきますので、
是非習得していってください。
 

選択中のシート:ActiveSheet

VBAを始めた方が、まず真っ先に使うのが、このActiveSheetです。

選択中、すなわちアクティブになっているシートですね。


ただしActiveSheetを使うと言っても、この書き方を使っているわけではなく、

Range("A1") = 1
Cells(1, 1) = 1

このように、セルの親シート指定を省略することで、
(半ば無意識に)ActiveSheetへの処理を書いています。


このActiveSheetの指定では、

  • 選択していないといけない
  • ユーザーが違うシートをアクティブにすると動かない
  • 複数のシートを扱うことができない

と、書けるマクロに限界がありますので、この壁に当たって、
ActiveSheetを卒業するためにこのページを訪れた方も多いかもしれません。


当たり前のように書いてきて、意識していなかった方も多いかもしれませんので、
卒業するためにも、ここで一度しっかりと意識しておきましょう。
 

Cells(1, 1) = 1

このコードは、

ActiveSheet.Cells(1, 1) = 1

これを省略した書き方であり、この時ActiveSheetという指定を使っています。

シートの名称で指定する:Worksheets("シート名")

ここから本題に入っていきます。

まずは一番わかりやすい「シート名での指定」です。

Worksheets("売上データ").Range("A1") = 1
Worksheets("集計表").Cells(1, 1) = 1

このように、Worksheets()のカッコ内にシート名を記載することで、
その名前のシートを指定することができます。


この方法のメリットは、とにかく分かりやすいことです。


マクロを書く際に、

シート見出し
↑これと、

Worksheets("集計表").Range("A1") = Worksheets("売上データ").Cells(R, 1)

↑これを見比べながらマクロを書けるので、
シート指定をミスしにくい、マクロ作成者に優しい方法です。


ぱっと見でも「なんかデータを集計してるマクロだな」と分かるのがいいですね。


一方デメリットは、シート名を変えられると動かなくなることです。

この方法でシートを指定する場合は、ユーザーのシート名変更に注意してください。

シートの並び順で指定する:Worksheets(シート番号)

続いてワークシートの並んでいる順番で指定する方法です。

Worksheet(1).Range("A1") = 1
Worksheet(2).Cells(1, 1) = 1

このように、Worksheets()のカッコ内に、シートの番号を記載することで、
左から数えてその番号にあるシートを指定できます。

このシート番号のことを、WorksheetのIndex番号と呼びますので、
気が向いたら覚えてあげてください。


この方法の超重要なメリットは、ループ処理に使えるという点です。

' 2~5番目の4つのシートすべてに同じ処理
Dim シート番号 As Long
For シート番号 = 2 To 5
    Worksheets(シート番号).Range("A1") = 1
Next

と、シート番号を変数にして、たくさんのシートに同じ処理を行うことができます。
 

' 2~10番目の中で、偶数番のシートだけを処理
Dim シート番号 As Long
For シート番号 = 2 To 10 Step 2 ' ←For文は増えていくカウントをStepで指定できる
    Worksheets(シート番号).Range("A1") = 1
Next

このように飛び飛びのシートをループしたりと、自在に組むことができます。


これはどんなに上達しても一生使うコードですので、きっちり習得しておきましょう。


対してデメリットが、

  • シートの並び順が変わるとちがうシートを処理してしまう。
  • どのシートを指しているのかコードだけではわからない

になります。


特に、違うシートを処理してしまうのは要注意です。


シート名指定のマクロで「シート名を変えちゃった」場合は、
せめてマクロはエラーで止まります。

しかし、シート番号指定で「シートの順番を変えちゃった」場合は、
下手するとエラーが出ないまま処理が進み、シートを破壊しかねません。


初心者の内は、エラーが出るのは嫌だと感じるかもしれませんが、
実は本当の恐怖は「エラーが出ないこと」です。

十分に注意してください。


この「読みづらい」「あぶない」の2大デメリットがあるので、

Worksheets(1).Range("A1") = Worksheets(2).Cells(R, 1)

と、ただベタ打ちの数字でこの指定方法を使うのはなるべくやめましょう。

確かに書きやすいので、即席マクロづくりに便利ではあるのですが、
長く使うマクロでこれをやるのは、後で読み返すのが困難な上に危険です。

ご利用は計画的に。


シート番号に限らず、プログラミングにおいて「書きやすさ」と「読みやすさ」がトレードオフだったときは、できるだけ「読みやすさ」の方を取るようにしましょう。

プログラムは書く時間よりも読む時間や書き換える時間の方が長く、
そして苦戦しますからね。


小ネタ:シート番号の変数名に「i」はダメ

この「インデックス番号のループ処理」を用いるコードで、

Dim i As Long
For i = 2 To 5
    Worksheets(i).Range("A1") = 1
Next

と、変数名に「i」を使っているコードをよく見かけますが、
これはなるべくやめた方が良いです。


理由は単純で、

' 2~5番目のシートの、A1~A4セルを処理
Dim i As Long
For i = 2 To 5
    For i = 1 To 4
        Worksheets(i).Cells(i, 1) = 1 ' ←これはダメ。シートもセルもiを使おうとしてダブってる
    Next
Next

と、あとあと「同じ名前の変数は1個まで」という決まりに困ることになるからです。


ワークシートは「何かの親オブジェクト」として登場することが多く、
 「シートを○○するマクロ」
ではなく、
 「シート内の△△を○○するマクロ」
を作ることが多いです。

△△は当然セルが多いですね。


この時、親側で一番使いやすい「i」を使ってしまうと、
もっとたくさん処理を書かなければいけないセルなどに「i」が使えない
のです。


一番ありがちなやらかしとしては、
今まで作ったコード同士をコピペ合体できない。゚(゚´ω`゚)゚。
なんて事態を往々にして招きます。


そんでもって、シートを「i」、行を「j」、列を「k」みたいに、
今まで書いたコードの「置換ができない1文字カウンタ」を、
ひとつひとつ手で書き換えてツギハギ対応していくと、
たぶん、いつか崩壊します(笑)
 
 

For シート番号 = 2 To 5
    For R = 1 To 4
        For C = 2 To 3
            Worksheets(シート番号).Cells(R, C) = 1
        Next
    Next
Next

このように、シート・行・列それぞれのカウンタを分かりやすい変数名にしておけば、
変数の取り違えも減らせますし、コピペ合体もとても楽になります。

なにより読みやすいですしね!


変数名にiを使うのは、真っ黒な画面で、メモリの中でガチャガチャやる、
普通の?プログラミング言語の文化です。

ワークシートやセルなど、目に見えているものを扱うExcelVBAでは、
その見えているものの名前をそのまま変数に使っちゃいましょう。


「カウンタ変数は、何のカウンタかわかるように命名する」と、
読みやすいコードが書けますよ。

シートのオブジェクト名で指定する

さてWorksheets("シート名")、Worksheets(シート番号)と来て、
三大シート指定方法の残りひとつが「シートのオブジェクト名」です。


簡単に言うと、
プログラマ専用のシート名をつけることができる機能」を利用します。


VBE(マクロを書くところ)を見渡してみてください。


シートのオブジェクト名

こんな場所がありますよね。

この「Sheet1 (集計表)」や「Sheet2 (売上データ)」という部分こそ、
シートのオブジェクト名が書いてあるところです。

  • Sheet2 がシートのオブジェクト名
  • 売上データ が実際のシート名

となります。

さて、このオブジェクト名であるSheet2は、自由に変更ができます


オブジェクト名の変更

↑ここをクリックすると出てくる、


オブジェクト名の変更

↑ここの(オブジェクト名)の部分を書き換えることで変更します。


分かりやすい様に同じ名前にしてみました↓
同じ名前に設定したオブジェクト名


この設定において、実際にマクロを書く際は、

売上データ.Range("A1") = 1
売上データ.Cells(1, 1) = 1

集計表.Range("A1") = 売上データ.Cells(R, 1)

と、このオブジェクト名をそのまま使ってWorksheetを指定することができるようになります。

短い上に超分かりやすいですね!


この機能はメリット盛りだくさんで、特に、

  • シートの指定が短く明確
  • シート名が変更されても大丈夫

が強力です。

このシートのオブジェクト名を使えるようになると、
とても分かりやすいコードを、スピーディーに書けるようになります。


長く使うようなマクロは、シートのオブジェクト名をきっちり設定しておきましょう。



ちなみにこのオブジェクト名ですが、ちょっとカッコつけて、

WSシート名というオブジェクト名

↑こんな風にオブジェクト名の頭文字に「WS」をつけると、

WS集計表.Range("A1") = WS売上データ.Cells(R, 1)

と、どのシートを指しているかを分かりやすく保ちつつ、
この変数が「Worksheetオブジェクト」であることを明確に
できます。


また、入力する際に、wsまで打って「Ctrl+Space」を押すと、

オブジェクト名の選択肢

↑このように、頭文字をそろえた効果で入力予測の選択肢から入力できるようになります。


この選択肢は、

シート見出し

↑これと候補が一致しますからね。


取り違えも起きづらく、読みやすく、書きやすいという、
最強のシート指定方法となります。

この命名法も、是非使ってみて下さい。



シート指定を短縮する方法を考える

さて、ワークシートを指定する方法は以上の3つとなります。

  1. Worksheets(シート名)
  2. Worksheets(シート番号)
  3. シートのオブジェクト名

でしたね。


では早速、これでコードを書いてみましょう。

Worksheets("売上データ").Cells(R, 1) = 商品名
Worksheets("売上データ").Cells(R, 2) = 価格
Worksheets("売上データ").Cells(R, 3) = 個数
Worksheets("売上データ").Cells(R, 4) = Worksheets("売上データ").Cells(R, 2) * Worksheets("売上データ").Cells(R, 3)

うーんしつこい(笑)

何度も何度も「売上データ」とうるさいですね。


シートのオブジェクト名を使うと、これよりは多少マシになりますが、
それでもしつこいことに変わりはありません。


ということで、シートを指定できたら、
その次は指定したシートを短縮で呼び出す方法を考えなければいけません。

↑のコードのしつこさを嫌って、
ActiveSheetに戻ってしまっては元の木阿弥ですからね。


その方法を3つ紹介していきます。

ワークシートを変数にSetする

上記のコードを、変数を使って以下のように書き替えます。

Dim ws As Worksheet
Set ws = Worksheets("売上データ")

ws.Cells(R, 1) = 商品名
ws.Cells(R, 2) = 価格
ws.Cells(R, 3) = 個数
ws.Cells(R, 4) = ws.Cells(R, 2) * ws.Cells(R, 3)

素晴らしく見やすくなりましたね!

変数「ws」をWorksheet用の変数として宣言(Dim)し、
Worksheets("売上データ")を、その変数にSetするコードです。


まず「このシートに処理をするよ!」と宣言をして、
そのあとで、処理を書いていくイメージのコードに出来ますね。


この変数へのSetは、オブジェクト名に対しても同じように使えます。

Set ws = WS売上データ

 

変数のいいところは、何個も作れて、名前も好きに付けられることです。

例えば2つのシートを扱う

Worksheets("集計表").Range("A1") = Worksheets("売上データ").Cells(R, 1)
Worksheets("集計表").Range("B1") = Worksheets("売上データ").Cells(R, 2)
Worksheets("集計表").Range("C1") = Worksheets("売上データ").Cells(R, 3)
Worksheets("集計表").Range("D1") = Worksheets("売上データ").Cells(R, 4)
Worksheets("集計表").Range("E1") = Worksheets("売上データ").Cells(R, 5)

↑このようなコードがあったときに、これを、

Dim ws取込 As Worksheet
Set ws取込 = Worksheets("売上データ")

Dim ws出力 As Worksheet
Set ws出力 = Worksheets("集計表")

ws出力.Range("A1") = ws取込.Cells(R, 1)
ws出力.Range("B1") = ws取込.Cells(R, 2)
ws出力.Range("C1") = ws取込.Cells(R, 3)
ws出力.Range("D1") = ws取込.Cells(R, 4)
ws出力.Range("E1") = ws取込.Cells(R, 5)

↑こんな風に変数を使って書きかえることができます。

指定したシートを「マクロの処理上での役割で名付ける」ことができましたね!


取込→出力というデータの流れが非常にわかりやすくなりますし、
 

ws取込.Range("E1") = ws出力.Cells(R, 5)

↑これを見て「あれ?バグじゃね?」と思えるのも大事なメリットです。


ワークシートに限らず、注目しているオブジェクトを変数にSetして扱う手法はとても便利です。

Worksheetはオブジェクト変数に慣れるとてもいい題材だと思いますので、
是非身につけていってください。

Withステートメントを使う

元コードを再掲します。

Worksheets("売上データ").Cells(R, 1) = 商品名
Worksheets("売上データ").Cells(R, 2) = 価格
Worksheets("売上データ").Cells(R, 3) = 個数
Worksheets("売上データ").Cells(R, 4) = Worksheets("売上データ").Cells(R, 2) * Worksheets("売上データ").Cells(R, 3)

 
このコードは、Withステートメントを使って、↓のように書き替えることができます。

With Worksheets("売上データ")
    .Cells(R, 1) = 商品名
    .Cells(R, 2) = 価格
    .Cells(R, 3) = 個数
    .Cells(R, 4) = .Cells(R, 2) * .Cells(R, 3)
End With

 
こちらもすごくわかりやすいですね。


Withステートメント「 With ○○ ~ End With 」に囲まれたエリアでは、
「.」1文字が○○を表すようになります。

↑のコードでは、「.」が「Worksheets("売上データ").」を表しています。


変数よりさらに短くなるので、見やすさで言ったら一番ですね!

Withステートメントは、Worksheetと非常に相性が良いので、
じゃんじゃん使っていきましょう。



ただし、デメリットは1つしか短縮できないことです。

2つのシートを扱う場合は、

With Worksheets("集計表")
    .Range("A1") = Worksheets("売上データ").Cells(R, 1)
    .Range("B1") = Worksheets("売上データ").Cells(R, 2)
    .Range("C1") = Worksheets("売上データ").Cells(R, 3)
    .Range("D1") = Worksheets("売上データ").Cells(R, 4)
    .Range("E1") = Worksheets("売上データ").Cells(R, 5)
End With

このように片方だけをWithすることしかできません。

これでもかなり見やすいのは間違いないのですが、
もっと長いマクロだと「どっちがWithだっけ?」問題が出てきます。

ご利用は計画的に。

おまけ:ワークシートを関数の引数に渡す

最後の方法は難易度が上がりますので、いきなり完璧に理解しようとしなくてよいです。


なんとなく見ておくだけでも、いつか必ず役に立つと思いますので、
適当に流し読みしてみてください。


例えば上記のコードは、こんな風に書き換えることもできます↓

Sub 売上データを登録して領収書を出力する

    Call 売上データに登録する(Worksheets("売上データ"))
    
    ~~この後マクロが続きます

End Sub


Sub 売上データに登録する(ws As Worksheet)

    ws.Cells(R, 1) = 商品名
    ws.Cells(R, 2) = 価格
    ws.Cells(R, 3) = 個数
    ws.Cells(R, 4) = ws.Cells(R, 2) * ws.Cells(R, 3)

End Sub

 
1つめのSubが、処理全体を行う、いわゆる「マクロの本体」で、
2つめのSubが、「売上データシートに対して処理を行う関数」です。

関数内のコードは変数wsに入れた時と全く同じです。


(ws As Worksheet)と、カッコに囲まれた部分が、
この関数「売上データに登録する」が、「wsを受け取りますよ~」という設定です。

実際に呼ぶときは、

Call 関数名(渡すもの)

と書いています。
この「渡すもの」を、関数の「引数」と呼びます。


wsにSetして扱う手法を、変数ではなく、関数の引数で行うこともできるということですね。


関数化のメリットは、ワークシートを変数に入れたように扱えることに加え、

Call 売上データに登録する(Worksheets("売上データ"))

この部分がメインマクロ上でたった1行になっていることです。


マクロが複雑になってくると、例えばFor~NextとかIf~Else~EndIfとかが、
めっちゃ口を開けたカバさんみたいに広がって何やってるのかわけわかんなくなることがあります。


この時、カバさんの口の中だけを関数にすることで、メインコードを極端に短くすることができます。

メインマクロでは口を閉じて、ループ文を泳ぐのに集中するようなイメージでしょうか。


関数というと難しい印象を受けますし、実際抽象的な話になるので、
「よし学ぼう!」と思っても、いい題材が無いとかなり難しい勉強を強いられます。

しかし、「シートの処理部分のパッケージ化」みたいな簡単な事例があると、
書き替えるような感じで眺めることができるため、案外とっつきやすいかもしれません。


いきなり組むのは難しいと思いますが、何となくイメージしておくだけでも将来取り組む時の糧になると思います。


いつかでっかいカバさんに困った時に、気が向いたら取り組んでみてください。

まとめ

以上でWorksheetの指定方法の解説を終わります。


まずは「シートを指定する方法」として、

  1. ActiveSheet
  2. Worksheets("シート名")
  3. Worksheets(シート番号)
  4. シートのオブジェクト名

を紹介しました。


そして、指定できたシートを短縮で記述するための、

  1. 変数にSetする
  2. Withでくくる
  3. 関数に分離する

を紹介しました。


WorksheetはExcelそのものといってもいいオブジェクトです。

ExcelVBAをやる上で、一生の付き合いになります。


仲良く二人三脚で、VBAライフを歩んでいきましょう。