オブジェクト変数を使おう。

マクロを動作させるのに、数値や文字列を変数に代入することは日常茶飯事です。
しかし実は、ワークシートやセルなどのオブジェクトも変数に代入することができます。

1.ワークシートを設定する。

ワークシートを変数に代入するためには、数値や文字列、論理値( True / False )の代入とは少し違った面があります。
それは、Dimステートメントで変数を宣言した後、実際の代入にSetステートメントを使うことです。

Sub test16()

  Dim R As Integer
  Dim C As Integer

  For R = 1 To 5
    For C = 1 To 5
      Cells(R+5, C+1) = Worksheets("元").Cells(R, C) ←@
    Next C
  Next R

End Sub
 
これは、オブジェクト変数を使っていないプロシージャです。


@ ここでは、「元」というワークシートのデータを
  今現在アクティブになっているワークシートに
  下に5行右に1列ずらして書き込んでます。 
Sub test17()

  Dim 元 As Worksheet ←A
  Dim R As Integer
  Dim C As Integer

  Set 元 = Worksheets("元") ←B

  For R = 1 To 5
    For C = 1 To 5
      Cells(R + 5, C + 1) = .Cells(R, C) ←C
    Next C
  Next R

End Sub
オブジェクト変数を使うと、このようになります。 


A ここで、ワークシートを代入できるよう宣言します。

B ここで、「元」という変数に、ワークシートを代入します。

C 記述するときは、オブジェクトとして使います。



日本語表記もしてあるので、すっきりとして見やすいです。
Sub test18()

  Dim 名前 As String ←D
  Dim R As Integer
  Dim C As Integer

  名前 = "元" ←E

  For R = 1 To 5
    For C = 1 To 5
      Cells(R + 5, C + 1) = Worksheets(名前).Cells(R, C) ←F
    Next C
  Next R

End Sub
 
ちなみに、文字列を使った場合は、こんなふうになります。


D 文字列として宣言します。

E 「元」という文字を、変数に代入します。

F ワークシートを扱うときには、ワークシート名として書きます。



オブジェクト変数を使った方が、見栄えがよくなります。

2.ワークシート名を取り出す。

オブジェクト変数を使うと、次のようなこともできます。
下のプロシージャは、アクティブになっているブックの全部のワークシート名を表示します。
これを応用すると、条件を満たすワークシートだけ処理したり、ワークシートの削除をしたりができます。

Sub test19()

  Dim Ws As Worksheet

  For Each Ws In Worksheets ←@
    MsgBox Ws.Name ←A
  Next Ws

End Sub
 
@ アクティブなっているブックの中から、
  1つ1つワークシートを呼び出します。
  呼び出したときに、Wsというオブジェクト変数に代入します。

A 呼び出したワークシートの名前を表示します。 

3.セルを扱う。

オブジェクト変数では、当然、セルも扱うことができます。
下のプロシージャでは、数値を偶数と奇数に分類しています。

Sub test20()

  Dim Rg As Range ←@
  Dim R As Integer

  For R = 2 To 11
    If Cells(R, 4) Mod 2 = 0 Then ←A
      Set Rg = Cells(R, 1) ←B
    Else
      Set Rg = Cells(R, 2) ←C
    End If

    Rg.Value = Cells(R, 4) ←D
  Next R

End Sub
@ ここで、セルを代入できるよう宣言します。

A 4列目の数値を2で割った余りで、
  処理を分岐します。

B 偶数の時は、1列目を代入します。

C 奇数の時は、2列目を代入します。

D セルの値に、4列目の値を代入します。
Sub test21()

  Dim R As Integer

  For R = 2 To 11
    If Cells(R, 4) Mod 2 = 0 Then
      Cells(R, 1) = Cells(R, 4)
    Else
      Cells(R, 2) = Cells(R, 4)
    End If
  Next R

End Sub
 
実際に、このようなプロシージャが必要になったときは、
左のように組む方が多いかもしれません。


ただ、読み込む位置を変更したりするとき、
(例えば、元データが5列目になった場合)
このプロシージャだと3カ所修正しなければなりませんが、
上のプロシージャだと2カ所で済みます。

行数の多いプロシージャになったとき、
その差はもっと大きなものになるので、
まとめることができるなら、
まとめた方がメンテナンスは楽になります。

4.範囲を扱う。

セルの扱いをもっと広げて、範囲として扱うこともできます。
次のプロシージャは、ある範囲の中でセルを選択し、アドレスを表示します。

Sub test22()

  Dim 範囲 As Range
  Dim Rg As Range

  Set 範囲 = Range("B3:D6") ←@

  For Each Rg In 範囲
    Rg.Select ←A
    MsgBox Rg.Address(ReferenceStyle:=xlR1C1) 'R1C1形式で ←B
  Next Rg

End Sub
 
@ 扱う範囲を設定します。
  プロシージャ内では、RangeとCellsを混在して使えるので、
  そのときの使い勝手がよい方を使うと便利です。

A ここで、セルを選択しています。

B ここでは、R1C1形式でアドレスを表示しています。
  A1形式で表示したければ、Rg.Address だけにします。 
Sub test23()

  Dim R As Integer
  Dim C As Integer

  For R = 3 To 6 ←C
    For C = 2 To 4 ←D
      Cells(R, C).Select
      MsgBox Cells(R, C).Address(ReferenceStyle:=xlR1C1) 'R1C1形式で
    Next C
  Next R

End Sub
 
ちなみに、範囲を使わないで書くと、こんな感じです。


ここで考えなければいけないのは、範囲が変更になったときです。
上のプロシージャであれば、@の内容を書き換えれば済みます。
ところが、このプロシージャだと、CとDを書き換えなければなりません。

このプロシージャはまだ処理が簡単ですが、複雑なものになると、
修正する箇所も莫大に増えてきます。
そうなると、メンテナンスにも非常に時間がかかります。


上のプロシージャで、行位置を知りたいときは、Rg.Rowで求められますし、
列位置を知りたければ、Rg.Columnで求められるので、不都合もありません。

5.オブジェクト変数が空かどうかを調べる。

 オブジェクト変数が空であることを調べる時は、「Is Nothing」を使います。
 したがって、Aというオブジェクト変数を調べる場合なら、
 If A Is Nothing Then Msgbox "空です。"
 と、こんな感じになります。

 反対に空でないことを調べる場合は、
 If Not A Is Nothing Then Msgbox "空ではありません。"
 となります。

データ型 空のとき 備考  (例) 空のとき (例) 空でないとき
オブジェクト型
Range,Worksheet
Nothing ないという意味。
(空にするときは、Set A = Nothing )
If A Is Nothing Then 〜  If Not A Is Nothing Then 〜 
数値型
Integer,Singleなど
1つもないので0。(数値としては存在します。)
(0にするときは、A = 0 )
If A = 0 Then 〜  If A <> 0 Then 〜  
文字列型
String
"" 長さが0の文字列が入っているという扱い。
(無しにするときは、A = "" )
If A = "" Then 〜 If A <> "" Then 〜