ド素人でも学べるExcelVBA講座 007 セルオブジェクト

ブログ

はじめに

 変数、繰り返し処理、条件分岐ときて、次はいよいよオブジェクトに入っていく。
 Excelの部品(シートやセル、図形など)はオブジェクトという形式で出来ているのだが、これは色々な機能を使いやすいようにパッケージ化したものになる。
 オブジェクトの内容はイメージしにくいと思うが、とにかく使ってみるのが一番の早道だろう。
 
 最初に取り上げるのは、最もよく使うセルオブジェクトの扱いになる。
 セルの使い方を通じて、オブジェクトの使い方を体験していこう。

セルのアドレス指定

 セルは Range オブジェクトを使う。ただ、Cells でも同じ事ができる。この2つはセルの位置の指定の仕方が違うだけで、ほぼ同じと考えて差し支えない。
 当然、どのセルを指しているのか指定する必要がある。

 オブジェクトに渡す値を「引数」という。
 Range と Cells では、セルの位置(アドレス)を指す方法が異なる。
 
 Range(”A3″)
 Cells(3 , “A”) 又は、Cells(3 , 1)

 
 両方ともA3セルを指しているが、括弧の中が引数でアドレスの書き方が異なっている。
 
 Rangeはセルの位置を文字列で指定する。セルの位置は、(“列行”) のように書く。
 (””で囲まれているのは文字列だ。文字列と数値をキチンと区別しよう。)

 Cellsは、行と列の2つの引数があり、(行,列)という順番で書く。行、列ともに数値で指定するが、列に関してはアルファベットの文字列で指定しても良い。
 
 以下の書き方は全て間違いだ。どこがいけないのかチェックしておこう。
 【全て間違った書き方】
 Range(A3) アドレスを文字列で指定していない
 Range(”A”3) 行が文字列になっていない
 Range(A”3″) 列が文字列になっていない
 Range(”13″) 列を指定していない(列は数値で表現できない)
 Range(”A”) 列しか指定していない
 Cells(“3” , “A”) エラーとはならないが行は文字列で指定する事はない
 Cells(“C” , “A”) 行の指定が良くない
 Cells(3 , “A1”) 列の指定が良くない
 Cells(”3A”) 引数は2つ必要 ※
 
 ※ Cells(3) と指定した場合、エラーは出ないが、少々複雑な説明が必要になるので、今は行,列の2つの引数が必要と覚えて欲しい。
 
 それぞれ、以下のようなテストコードで試してみよう。
 Debug.print に続けて下線部分に当てはめてみれば良い。
 どんなエラーとなるかはお楽しみだ。エラーが出たら「終了」ボタンで終了しよう。

Sub testCell()
  Debug.Print Range(A3)
End Sub

よく使うアドレス指定方法

 Range や Cells のアドレス指定は、変数を割り当てるなどして使用する事が多い。以下のような書き方は良く行うので慣れるようにしよう。
 以下のプログラムはすべて、現在開いているシートのA3セルの値を、イミディエイトウィンドウに表示するコードだ。A3セルに値(文字列や数値)を入れてプログラムを実行してみよう。

Sub testRange()
    '行が数値だが、&で文字列連結している
    Debug.Print Range("A" & 3)
End Sub
Sub testRange2()
    '行に変数を指定して、&で文字列連結している
    Dim i As Long
    i = 3
    Debug.Print Range("A" & i)
End Sub
Sub testRange3()
    'アドレスを文字列変数にして、指定している
    Dim s As String
    s = "A3"
    Debug.Print Range(s)
End Sub
Sub testCells()
    '行を変数で指定している
    Dim i As Long
    i = 3
    Debug.Print Cells(i, "A")
End Sub
Sub testCells2()
    '列を変数で指定している
    Dim i As Long
    i = 1
    Debug.Print Cells(3, i)
End Sub

 変数を利用してアドレスを指定すれば、後から好きなセルに値を代入できるようになる。
 繰り返し処理や条件分岐で好きなセルを選択することもできる。

Rangeは複数のセルを選択できる

 Rangeは複数セルを選択する書き方ができるのが特徴的だ。
 セルを複数指し示すには、以下のように文字列で始点と終点を:(コロン)で繋いで書く。
 “A1:B3”
 この場合、始点は左上、終点は右下のセルになる。

Sub testRangeSelect
    Range("A1:B3").Select
End Sub

 SelectRangeに対する命令(メソッド)になる。
 RangeSelectの間にドット(.)がある所に注目してほしい。
 このようにオブジェクトに対する命令(メソッド)属性(プロパティ)は、ドットで繋ぐの覚えておいてほしい。
 
 上記のプログラムは、「A1からB3の範囲を選択しなさい。」という事だ。実行すると、A1からB3の範囲が選択されるのが確認できる。

 アドレスの範囲指定は、変数に割り当てることもできる。
 例をあげてみよう。

Sub testRangeSelect2()
    Dim i As Long, j As Long
    i = 1
    j = 3
    Range("A" & i & ":B" & j).Select
End Sub

 ここでは、始点と終点を変数で指定している。
 文字列の連結は問題なくできるだろうか?
 上手くいかなかった人は 引数に渡した値(文字列)を Debug.print で確認してみるといい。

Sub testRangeSelect2a()
    Dim i As Long, j As Long
    i = 1
    j = 3
    Debug.Print "A" & i & ":B" & j
    Range("A" & i & ":B" & j).Select
End Sub

RangeとCellsの使い分け

 RangeとCellsは、同じような使い方ができると言ったが、なぜこのように2つの書き方が出来てしまうのだろうか?
 筆者が初心者の頃は、Cellsの方が使いやすいと感じていたので、Rangeを使う事は稀だった。(というか使わないようにしていた。)しかし世の中にはRange派の人たちもいて、Cellsなんて必要ないと考えていたようだ。
 
 まるで宗教戦争のような話で、何事もRangeで書きたがるコードをCells派の人たちは「何て見にくいコードなのだろう」と忌み嫌っていた。
 (もちろんRange派の意見は逆だ。)
 
 この低次元の争いの原因は、片方だけ覚えれば他方は覚えなくて良いという怠け根性から来ているのだと思う。
Cellsばかり使っていた筆者は、Rangeの事まで覚えるのは面倒だっただけなのだ。
 
 実は2つの書き方を覚えて、きちんと書き分ければプログラムコードはとても見やすくなる。
 つまり「どちらでも良い」のではなく、意味合いを持たせて書いた方が「より良い」という事だ。
 
 Rangeと言うのは、絶対的な位置指定複数セルの指定に向いている。
 Cellsは、相対的な位置指定に向いている。

 
 具体的には、参照位置が変わらないのならRangeを、参照位置が変化していくならCellsを使うようにするのが良いという事だ。
 そうすると、For文には、Cellsを使うべきだという事になる。それ以外で参照位置が変わらないのであれば、積極的にRangeを使っていけばよい。
 (これはあくまで筆者の流儀だ。)
 
 そのようなルールを自分の中に持っていれば、Rangeが出てきた時に、ここは固定的に参照するんだな。という意思表示にもなる。

 必ずしも筆者のルールに従う事はないが、プログラムコードはプログラマーの意思表示が現れてくる。
 初心者のうちはエラーが出ないコードを書くので精一杯かもしれないが、慣れてきたら「こう書いた方がわかりやすいのではないか」という余裕も出てくるだろう。
 プログラムコードのわかりやすさを求めるのは、他人であるかもしれないが、書いた本人が後から見直すケースが殆どだ。自分のためにもわかりやすいプログラムコードを書く事を心がけるようにしよう。

 セルの位置(アドレス)を指定できるようになったので、今度は値の代入と取得の仕方をみていこう。
最初に言っておくと、セルへ値を代入するのは簡単だが、セルの値を取得するのは少々厄介だ。

セルへの代入

 代入する値には、文字列や数値、日付など様々な種類があるが、セルは勝手に型を判断して受けてくれるため細かい事を気にせずに値を代入できる。
 例を示す。

Sub testCell()
    Range("A3") = "Hello"
    Range("A4") = 123
    Range("A5") = "2024-8-10"
    Range("A6") = "123"
End Sub

 Range や Cells を左辺に置いて、= で右辺に代入したい値を指定すれば良いだけだ。
 ここで注目したいのは、文字列でも数値でも代入する事が可能だという点だ。
 結果は、以下のようになる。

 A3セルは、文字列が入力されている。
 A4セルには、数値の 123 が入力されている。(右詰めになっている。)
 A5セルは、”2024-8-10″と代入したが、表示は 2024/8/10 と日付型に変わって代入されている。(セルの書式設定で確認できる。)
 A6セルでは、”123″と文字列を代入したが、数値に変換されて代入された。

 
 A5セルとA6セルでは、自動変換されたと捉えた方が良いだろう。
 試しに別のセルで”2024-8-10″と手入力してみてほしい。 2024/8/10 と日付型に変わるはずだ。
 今度は、別のセルで”123” と全角で手入力してみよう。こちらも 123 と数値に変換された。
 
 このようにセルへの代入では、Excelが行う自動変換を考慮しなければならないケースがある。
 ただ、自動変換を便利な機能と捉える事もできるから、慣れてきたら大いに使うようにしよう。

セルの値の取得

 今度は、セルの値を受け取る方法だ。
 以下のようにシートの C1~C5 に適当に数値を配置する。

 では、これらの合計を計算するプログラムを書いてみよう。

Sub testCell2()
    Dim i As Long, total As Long
    For i = 1 To 5
        total = total + Cells(i, "C")
    Next i
    Range("C6") = total
End Sub

 最初に、繰返しのカウント用変数 i と、合計を保持する total を数値型で宣言している。
 次にFor文で、値の入っているC列の1~5行目を巡回して、それぞれの値を total に追加していく。
 
 total = total + Cells(i, “C”) という書き方は大丈夫だろうか?

 この式は、右辺の値を計算してから左辺に代入するから、C1セルからの値を逐次合計していることになる。
 For文を抜けると total には合計値が入っているので、それをC6セルに代入している。

 実行すると C6にC1~ C5までの値の合計が入っているのがわかる。

 問題なく合計が計算されたが、ここでC1~ C5までのセルのどれかを文字列に変えてみよう。
 (以下のようにC3セルを”abc” としてみた。)

 実行すると、「型が一致しません」というエラーが発生する。
 (メッセージは、「終了」ボタンで終了してしまって構わない。)

 このエラーが示しているのは、C3セルの値を 数値型の変数 total に入れようとしたら型が違ったというものだ。
このように、プログラムする上で「型」というのは重要な要素になる。
 セルは色々な型の値を受け入れてくれるが、それを取り出す時にはどんな型が入っているか分からない。

 このようなケースが予想される場合は、セルの型を見極めてから値を代入するという方法もある。
ただ、実際には、数値のデータが並んでいるという事を見越してプログラムを組むケースが殆どだ。

 いい加減に思われるかもしれないが、細かいエラーの対処を行うために何行ものプログラムコードを書くのは結構大変な作業となる。それならばいっそエラーを吐いてもらってプログラムが止まってもらった方がデータの不具合にも気付けるという考え方だ。

値の転記

 次はA列の値をB列に転記してみよう。

プログラムは以下のようになる。

Sub testCell3()
    Dim i As Long
    For i = 1 To 6
        Cells(i, "B") = Cells(i, "A")
    Next i
End Sub

1~6 行までの A列の値を B列に転記している。結果は以下の通りだ。

 ほとんどがそのまま転記されているが、5行目の日付のみ変な値になっている。
 これはどういう事だろうか?
 実は、日付というのは扱いに工夫が必要となる。

 ExcelVBAでは、日付型は、シリアル値※と書式設定で日付を表現している。このため値のみの転記では、シリアル値が転記されるだけなのだ。
 試しに、B5のセルの書式設定を「日付」に変更してみてほしい。
 書式設定を変更すれば、A5セルと同じ日付になる。

 ※この場合のシリアル値とは、1900年1月1日を 1 とした、通し番号の事。

 さて、これまで筆者は「値」という言葉を使ってきた。実はセルが持っているのは「値」だけではないのだ。
 セルには「値」と同じような属性(プロパティ)が他にもある。

 Rangeオブジェクトのプロパティ
 ・値
 ・アドレス
 ・フォント
 ・背景色
 ・文字色
 ・書式設定
 ・数式
 ・枠線
  などなど、、、、
 
 本来なら、Rangeのプロパティに対して値を代入したり、読み込んだりするのだが、「値」に関しては省略できる事になっている。
 つまり、「値」プロパティは特別扱いされているわけだ。
 
 前に書いたプロシージャを省略なして書くと以下のようになる。

Sub testCell2()
    Dim i As Long, total As Long
    For i = 1 To 5
        total = total + Cells(i, "C").Value
    Next i
    Range("C6").Value = total
End Sub

 Range も Cellsも基本的に同じで、「値」のプロパティの場合は、本来なら .Value と付ける。
 
 以前、変数の所でも「変数型を省略した場合は、バリアント型になる」と説明したが、Range や Cellsの場合は、プロパティを省略したら .Value を指定したのと同じになる。

 このようにVBAでは、省略できる事柄が結構多い。利点としてはプログラムコードを簡潔に書く事ができるが、欠点としては何が省略されているか分からないと思わぬミスを招いてしまう。

省略されていること

 以下のようなプログラムコードがあったとする。
 
 Range(“C1”).Value = 123

 これは、C1セルに 123 という数値を代入している。これは説明した通りだ。
 では、どのシートのC1セルを指しているのだろうか? シートはブック内に複数ある事もある。
 さらに言うなら、Excelブックが複数開いている事だってある。その場合はどのブックを指すのだろうか?
 
 答えは、現在アクティブになっているブックのアクティブシートのC1セルになる。
 
 ActiveWorkbook.ActiveSheet.Range(“C1”).Value = 123
 
 本来であれば、上記のように書くべきなのだが、現在開いているブックが対象であれば、ActiveWorkbook を省略する事ができ、
 
 ActiveSheet.Range(“C1”).Value = 123

 更に、現在開いているシートが対象であれば、ActiveSheet を省略できる。
 
 Range(“C1”).Value = 123

 初心者は、とりあえず省略されてる部分があるのだという事を頭の片隅に置いておいてほしい。
 もし、別のシートのセルを対象にしたいのであれば当然省略はできない。さらに、別のブックという事であれば、ブック、シート共に省略はできない事になる。
 その事は今後学習が進んでから学ぶことにしよう。

まとめ

 セルの扱いについては、もっと長くなりそうなので、ここで一回区切りとする。
 今回学んだことをまとめておこう。

 ・Range と Cells の引数指定
 ・Range と Cells の特徴と使い分け
 ・セルへの値の代入や取得は変数型に注意が必要
 ・日付型の扱いに注意
 ・プロパティ値 Value の省略
 ・アクティブブック、アクティブシートの省略
 
 次回もRange と Cells の扱いについて見ていく予定だ。
 とても大事な要素なので丁寧に進めていこうと思う。


コメント

タイトルとURLをコピーしました