古庄 潤(ふるしょう じゅん)

本業はエンジニア。ICに様々な機械をつなぎ,電流やら電圧を測定する。もちろん,これらの測定器もVBAでコントロールし,取り込んだデータもマクロで処理する。人呼んで,マクロの鬼軍曹!

診断(5)
複数のコントロールを配列のように処理する

「じゃ~ん!どうじゃ,ゲール君」
「おや,先生,スーツなんか着てどうしたんですか?」
「うむ,姪っ子の結婚式にと思ってな,新調したんじゃ。似合うか?」
「う~ん…ちんぴらか,悪徳刑事にしか見えませんね」
「な,なんじゃと!」
「文句なら御両親にどうぞ」
「ぐれてやる!」
「はいはい。さ,お仕事しましょ」

今月の相談
「作成したユーザーフォームにたくさんのラベル(Label)があって(図1),それらのキャプション(Caption)を結合するマクロを作成しました。機能は実現しましたが,エレガントにはほど遠い冗長なコードになってしまいました(リスト1)。このラベルを配列のように処理することはできないでしょうか?」

図1●ラベルだらけのユーザーフォームのサンプル
図1●ラベルだらけのユーザーフォームのサンプル
[画像のクリックで拡大表示]


Private Sub CommandButton3_Click()
  Dim str8BIT As String

  str8BIT = str8BIT & Me.Label1.Caption
  str8BIT = str8BIT & Me.Label2.Caption
  str8BIT = str8BIT & Me.Label3.Caption
  str8BIT = str8BIT & Me.Label4.Caption
  str8BIT = str8BIT & Me.Label5.Caption
  str8BIT = str8BIT & Me.Label6.Caption
  str8BIT = str8BIT & Me.Label7.Caption
  str8BIT = str8BIT & Me.Label8.Caption
  MsgBox "1 番目 : " & str8BIT
  str8BIT = ""

  str8BIT = str8BIT & Me.Label9.Caption
  str8BIT = str8BIT & Me.Label10.Caption
  str8BIT = str8BIT & Me.Label11.Caption
  str8BIT = str8BIT & Me.Label12.Caption
  str8BIT = str8BIT & Me.Label13.Caption
  str8BIT = str8BIT & Me.Label14.Caption
  str8BIT = str8BIT & Me.Label15.Caption
  str8BIT = str8BIT & Me.Label16.Caption
  MsgBox "2 番目 : " & str8BIT
  str8BIT = ""
    ・
    中略
    ・

  str8BIT = str8BIT & Me.Label57.Caption
  str8BIT = str8BIT & Me.Label58.Caption
  str8BIT = str8BIT & Me.Label59.Caption
  str8BIT = str8BIT & Me.Label60.Caption
  str8BIT = str8BIT & Me.Label61.Caption
  str8BIT = str8BIT & Me.Label62.Caption
  str8BIT = str8BIT & Me.Label63.Caption
  str8BIT = str8BIT & Me.Label64.Caption
  MsgBox "8 番目 : " & str8BIT
  str8BIT = ""
End Sub
リスト1●複数のラベルのキャプションを結合するコード。Labelコントロールを一つずつ記述しているので,非常に冗長になっている

「ふむ,ビット列の一つひとつをラベルで表しているわけじゃな。ラベルのイベントプロシジャを使って,クリックすると“0”と“1”が反転するようになっておる。そして,ボタンをクリックすると,8ビットごとにまとめて(キャプションを連結して)メッセージとして表示する──と。なるほどな。確かに,リスト1の書き方では冗長過ぎる。複数のコントロールを操作するほうは,あるオブジェクトを使えば,もっとすっきり書ける…が…」
「先生,何か問題でもあるんですか?」
「うむ,多数のコントロールを配列のように扱うことでコードを簡略化する方法はある。Visual Basicと同じ様にはいかんがの。しかし,イベントプロシジャについては,どうにもならん」
「それは,どういうことですか?」
「とりあえず,解決できるところから説明しよう」

 VBA(Visual Basic for Apllications)は,Visual Basic(VB)の言語仕様に準拠しているので,VBのユーザーはそのスキルをおおむねVBAで活用できます。しかし,VBとVBAには相違点もあります。今回の問題は,その相違点の一つです。

 VBでは,コントロールを配列として定義することができます。例えば,多数のLabelコントロールを,
Label1(0)
Label1(1)
Label1(2)


Label1(62)
Label1(63)
といった具合に定義できます。当然,これらは処理の中で配列として扱うことができます。具体的には,リスト1の処理は,リスト2のように簡略化できます。


Sub MAKE_8BIT_DATA()
  Dim i As Integer
  Dim j As Integer
  Dim str8BIT As String

  For i = 0 To 7
    For j = 0 To 7
      str8BIT = str8BIT & Form1.Label1(j + (i * 8)).Caption
    Next j
    MsgBox i + 1 & " 番目 : " & str8BIT
    str8BIT = ""
  Next i
End Sub
リスト2●VBの記述例(複数のラベルのキャプションを結合)。VBは,複数のコントロールを配列として定義できるので,簡潔に記述できる

 見ておわかりの通り,Label1のインデックス・ナンバーに,ループのカウンタ変数iとjを使うことで,配列として処理しています。

  (j + (i * 8))
この計算式で,Label1のインデックス・ナンバーは,0~7,8~15…56~63と変化し,Label1(0)~Label1(63)までのキャプションを順番に取得します。

 しかし,VBAでは,ユーザーフォームに配置するコントロールは,配列として定義することができません。配列として定義するためのIndexプロパティがないのです。

 そこで,VBAの場合は,ControlsコレクションのControlsプロパティを使い,その引数に一工夫することで,ユーザーフォーム上のコントロール群を,あたかも配列であるかのように扱うことができます。

 Controlsコレクションは,ユーザーフォーム上のすべてのコントロールを含むコレクションです。Controlsプロパティの引数にコントロール名を与えることで,任意のコントロールを取得できます。CommandBarControlsコレクションを取得するControlsプロパティとは別物ですので,混同しないように注意してください。


Private Sub CommandButton3_Click()
  Dim i As Integer
  Dim j As Integer
  Dim str8BIT As String

  For i = 0 To 7
    For j = 1 To 8
      str8BIT = str8BIT & _
        Me.Controls("Label" & CStr(j + (i * 8))).Caption
    Next j
    MsgBox i + 1 & " 番目 : " & str8BIT
    str8BIT = ""
  Next i
End Sub
リスト3●VBAの解決例(複数のラベルのキャプションを結合)。ControlsコレクションのControlsプロパティを使い,引数のコントロール名(ラベル名)に一工夫することで,配列であるかのように処理している。リスト1の処理は,このように簡潔になる。

 ループの中で,順番にLabelオブジェクトを指定するためのカウンタ変数iとjを使う計算式は,リスト2と同じです。しかし,Controlsコレクションから任意のコレクションを取得する引数は,コントロール名ですので,計算式で得た数値をCstr関数で文字列に変換し,文字列「Label」と結合します。これにより,Label1~Label64を順次取り出すことができます。