前回は、ワークシート上に疑似LEDを1つ作成し、点滅させる処理を実装した。今回は、複数の疑似LEDを扱うことで、より実用的な構造の設計について考えてみる。
コード1では、LEDの各属性(セルの位置・色・点灯時間・消灯時間)をそれぞれ配列変数として定義し、LEDごとの設定値をインデックスで管理している。値の代入には、専用のプロシージャ SpecSetLED() を追加した。
Sub main にカーソルを合わせて F5 キーを押すと、図1. のとおりワークシート上に3つの疑似LEDが作成される。再度 F5 キーを押すと、それらが順番に点滅を開始する。SpecSetLED() の引数を変更することで、LEDの位置や点滅時間、表示色といった属性を自由に調整できる。

コード1. 配列による変数の管理
' 疑似LED定義用の配列変数
Public R(1 To 3) As Integer ' LEDセルの行番号
Public C(1 To 3) As Integer ' LEDセルの列番号
Public Col(1 To 3) As Long ' LEDの表示色
Public T_on(1 To 3) As Long ' 点灯時間(ミリ秒)
Public T_off(1 To 3) As Long ' 消灯時間(ミリ秒)
' LEDの属性を配列に設定するプロシージャ
Sub SpecSetLED(LED_Number As Integer, LED_Row As Integer, LED_Column As Integer, LED_Color As Long, LED_Time_On As Long, LED_Time_Off As Long)
R(LED_Number) = LED_Row ' セルの行番号
C(LED_Number) = LED_Column ' セルの列番号
Col(LED_Number) = LED_Color ' LEDの色
T_on(LED_Number) = LED_Time_On ' LEDの点灯時間(ミリ秒)
T_off(LED_Number) = LED_Time_Off ' LEDの消灯時間(ミリ秒)
End Sub
' LEDの初期描画(消灯状態)
Sub makeLED(LED_Number As Integer)
With Cells(R(LED_Number), C(LED_Number))
.Font.Color = Col(LED_Number)
.Value = "*"
.HorizontalAlignment = xlCenter
.Interior.Color = vbBlack
End With
End Sub
' LEDの点滅処理
Sub BlinkLED(i As Integer)
Dim t As Long
Cells(R(i), C(i)).Value = "●"
t = Timer * 1000
While Timer * 1000 < t + T_on(i): DoEvents: Wend
Cells(R(i), C(i)).Value = "*"
t = Timer * 1000
While Timer * 1000 < t + T_off(i): DoEvents: Wend
End Sub
' メイン処理
Sub main()
' LEDの属性を設定
Call SpecSetLED(1, 1, 1, vbRed, 500, 500) ' セルR1C1,赤色,点灯0.5秒,消灯0.5秒
Call SpecSetLED(2, 2, 2, vbYellow, 200, 200) ' セルR2C3,黄色,点灯0.2秒,消灯0.2秒
Call SpecSetLED(3, 3, 3, vbGreen, 100, 100) ' セルR3C3,緑色,点灯0.1秒,消灯0.1秒
' LEDの初期描画
Dim i As Integer
For i = 1 To 3
Call makeLED(i)
Next i
Stop ' 実行を一時停止(F5で続行)
' LEDの点滅ループ
Do
For i = 1 To 3
BlinkLED i
DoEvents
Next i
Loop
End Sub
このように、配列を使えばインデックスを利用してLEDの数を柔軟に管理でき、同じ種類のLEDを複数扱うことが可能です。しかしLEDとは異なる別のモノ、たとえばバーグラフのような表示要素をセルに追加したい場合、セルの位置を示す R() や C() は既に使われているため、変数名を変えなければならない。
扱うモノの種類や属性が増えるにつれ、変数の数も増加し、管理が煩雑になっていく。このような構造の煩雑さを解消するために、より意味のあるまとまりとしてデータを扱える方法が求められる。
こうした課題を解決するために、多くのプログラミング言語には「構造体」という仕組みが用意されている。もちろん、VBAでも Type ステートメントを使って構造体を定義できる。コード2は、LEDの属性となる変数をひとまとまりの構造体として記述した例である。
コード2. 構造体による変数の管理
' 疑似LEDの構造体定義
Public Type LED
R As Integer ' LEDを配置するセルの行番号
C As Integer ' LEDを配置するセルの列番号
Col As Long ' LEDの表示色
T_on As Long ' LEDの点灯時間(ミリ秒)
T_off As Long ' LEDの消灯時間(ミリ秒)
End Type
' LEDオブジェクトの宣言
Public LED1 As LED
Public LED2 As LED
Public LED3 As LED
' LEDの属性を構造体に設定するプロシージャ
Sub SpecSetLED(ByRef led As LED, LED_Row As Integer, LED_Column As Integer, LED_Color As Long, LED_Time_On As Long, LED_Time_Off As Long)
led.R = LED_Row
led.C = LED_Column
led.Col = LED_Color
led.T_on = LED_Time_On
led.T_off = LED_Time_Off
End Sub
' LEDの初期描画(消灯状態)
Sub makeLED(ByRef led As LED)
With Cells(led.R, led.C)
.Font.Color = led.Col
.Value = "*"
.HorizontalAlignment = xlCenter
.Interior.Color = vbBlack
End With
End Sub
' LEDの点滅処理
Sub BlinkLED(ByRef led As LED)
Dim T_now As Long
Cells(led.R, led.C).Value = "●"
T_now = Timer * 1000
While Timer * 1000 < T_now + led.T_on: DoEvents: Wend
Cells(led.R, led.C).Value = "*"
T_now = Timer * 1000
While Timer * 1000 < T_now + led.T_off: DoEvents: Wend
End Sub
' メイン処理
Sub main()
' LEDの属性を設定
Call SpecSetLED(LED1, 1, 1, vbRed, 500, 500)
Call SpecSetLED(LED2, 2, 2, vbYellow, 200, 200)
Call SpecSetLED(LED3, 3, 3, vbGreen, 100, 100)
' LEDの初期描画
Call makeLED(LED1)
Call makeLED(LED2)
Call makeLED(LED3)
Stop ' 実行を一時停止(F5で続行可能)
' LEDの点滅ループ
Do
Call BlinkLED(LED1)
Call BlinkLED(LED2)
Call BlinkLED(LED3)
DoEvents
Loop
End Sub
構造体を使えば、LEDの属性をひとまとまりにして扱えるため、種類が増えても変数名の重複を気にする必要がない。以下は、LEDとは異なる種類のオブジェクト(ここではプログレスバー)を構造体で定義した例である。セルの位置を示す変数 R、C を同じ名前のまま使用できる。
コード3. 構造体を二種類定義した場合
' 疑似LEDの構造体
Public Type LED
R As Integer ' LEDを配置するセルの行番号
C As Integer ' LEDを配置するセルの列番号
Col As Long ' LEDの表示色
T_on As Long ' LEDの点灯時間(ミリ秒)
T_off As Long ' LEDの消灯時間(ミリ秒)
End Type
' プログレスバーの構造体
Public Type BAR
R As Integer ' バーを配置するセルの行番号
C As Integer ' バーを配置するセルの列番号
V_max As Long ' 最大値
V_now As Long ' 現在値
End Type
疑似LEDを「モノ=オブジェクト」と捉えるならば、構造体はその属性をひとつにまとめる手段として有効である。扱うモノの種類が増えても管理が容易であり、これはオブジェクト指向設計への第一歩とも言えるだろう。