Visual Basic 6.0 初級講座
VB6対応

 

Visual Basic 中学校 > VB6 初級講座 >

第20回 配列2 コントロール配列

 

今回は前回やった配列を、コントロールに対しても使う方法を説明します。とはいっても前回の内容を読んでいなくても大丈夫だと思います。

私はVBを始めたころ、このコントロール配列を知らないばっかりにとんでもなく面倒くさい方法でプログラムしていました。当時200行以上にわたって書いていたコードは、コントロール配列を使えば0行ですむものだったのです・・・・・・・・。

 

1.画像をすばやく表示させる

 

これを読んでいるみなさんはすでにご存知だと思いますが、VBでファイルから読み込んで画像を表示させるには普通はLoadPicture関数を使うことでしょう。たとえば、C:\Windows\雲.bmp という画像を表示させるには次のように記述するのでしたね。(もちろんあらかじめフォームにピクチャーボックスを配置してあることが前提です)。


Picture1.Picture = LoadPicture("C:\Windows\雲.bmp")
 

実際のところこれで十分な場合がほとんどでしょうが、実はこの方法で画像を読み込むのには時間がかかります。パッパッパっとすばやく画像を変えたいときには向いていません。

では、すばやく表示させるにはどうするかというと、画像が必要になる前に読み込んでおくのです。たとえば、下のような3つの画像をすばやく切り替えて表示する方法を説明しましょう。(これが、あとでコントロール配列の説明をする布石になります)。

   

このくらい小さな画像ならLoadPicture関数で読み込んでもそんなに時間はかからないと思うのですが、そこは説明のためです。手近に画像がない方はこの3つの画像をダウンロードして使ってください。(ダウンロードするには画像の上で右クリックして、「名前を付けて画像を保存」を選択します。ただし、IE以外のブラウザのことはよくわかりません)。

あとのことも考えて、少ししっかりとプログラムを作って見ます。

まず、フォームにイメージコントロールを3つ配置してください。そして、3つともVisibleプロパティをFalseにします。つまり、実行時には見えなくしてしまうわけです。

次に、コマンドボタンを3つ配置して、それぞれのCaptionプロパティを「晴」「雨」「雪」としてください。このボタンを押すとそれぞれの画像が表示されるようにあとでプログラムします。

最後に画像を表示するためのピクチャーボックスを1つ配置してレイアウトは終了です。

それが終わったらいよいよコードを記述します。まず始めに、この3つの画像を読み込んでしまいます。画像のアドレスはここでは適当にしておきますので、アドレスの部分は皆さんの環境に合わせて変えてください。

Private Sub Form_Load()

Image1.Picture = LoadPicture("C:\hare.gif")    '晴の画像を読み込む

Image2.Picture = LoadPicture("C:\ame.gif")    '雨の画像を読み込む

Image3.Picture = LoadPicture("C:\yuki.gif")    '雪の画像を読み込む

End Sub

これで、それぞれのイメージコントロールにそれぞれの画像が読み込まれるわけですが、VisibleプロパティをFalseにしているので画面には表示されません。

次に、3つのコマンドボタンに、それぞれ次のように記述すれば完成です。

Private Sub Command1_Click()

Picture1.Picture = Image1.Picture

End Sub

Private Sub Command2_Click()

Picture1.Picture = Image2.Picture

End Sub

Private Sub Command3_Click()

Picture1.Picture = Image3.Picture

End Sub

完成したらプログラムを実行して確かめてみてください。ボタンを押すと画像が切り替わりますね?

さて、ボタンをクリックしたときの処理をPicture1.Picture=LoadPicture("C:\hare.gif")のようにしても同様のことができますが、画面が切り替わるときに少しもたつきます。つまり速度が遅いのです。どのくらい差があるか比べてみましょう。

For Nextを使って、自動的に画像1000回切り替えてみました。この実験をしたプログラムを見たい人はここをクリックしてください。今は結果だけを説明しますと、LoadPicture関数を使って切り替えた場合要した時間はトータルで、13.022秒。使わないで画像を切り替えた場合は、3.99秒。実に3倍以上のスピードの差があるわけです。

ゲームなどを作るときに頻繁に使う画像はその都度ファイルから読み込むのではなく、最初に読み込んでおきましょう。しかし、一度に大量の画像を読み込むとメモリに負担がかかりますので気をつけてください。

 

2.コントロール配列の導入

 

いよいよ今回のテーマ「コントロール配列」の説明に入りましょう。今作ったプログラムをもう一度よく考えてみると、実は次のような処理をしているということがわかります。

Command1をクリックする → Picture1 に Image1 の画像を表示する。

Command2をクリックする → Picture1 に Image2 の画像を表示する。

Command3をクリックする → Picture1 に Image3 の画像を表示する。

同じような処理を3つに分けているのですね。これが非能率的だといわれるものです。3つくらいだからがまんしてプログラムもできますが、番号だけ違って中身は同じ処理が100個も200個もあったらいちいち打ち込むのは大変です。

そうはいってもWindowsには必殺のカット&ペースト、つまり「コピーと貼り付け」があるのだから意外と楽だよという人も中にはいるかもしれません。しかしですよ、もし、あとになって、ほんの些細な点を修正する必要に迫られたときに、また100個も200個も似たような修正をするのはとても大変です。それに、プログラムにバグがないかテストするのも死ぬほど大変です。

この処理は要するに、

CommandKをクリックする → Picture1 に ImageK の画像を表示する。

という処理なのだから、そのように1つにまとめて書きましょうというのが「コントロール配列」の基本的な考え方です。

やりたいことは次のようなコードです。ただし、下のコードを実行するとエラーになってしまいます。

Private Sub CommandK_Click()

'このプログラムは間違いです

Picture1.Picture = ImageK.Picture

End Sub

なぜ、エラーになるかというと、「ImageK」とい名前のコントロールが配置されていないからです。さぁ、コントロールを配列のように数字で扱うにはどうしたらよいのでしょうか。

こたえは、Indexプロパティです。

Image1,Image2,Image3の名前をすべて MyImage という同じ名前にしてください。名前はプロパティボックスの(オブジェクト名)という欄で変えることができます。ただ、普通やると同じ名前をつけることはできません。そこで、それぞれのIndexプロパティを 1, 2, 3 にしてみてください。Indexプロパティの数字が違うのなら同じ名前をつけることができるようになります。

これで、MyImage という名前のイメージコントロールの配列が完成しました。いままでImage1と書いていた代わりにMyImage(1)と書くことでイメージコントロールを参照できます。

ちなみに、普通は一度配置してから名前とIndexプロパティを変更するのは面倒くさいので、まず、1つ配置してから、そのコントロールをコピーして貼り付けます。そうするとVBがコントロール配列にするかどうかきいてくるので はい と答えると自動的にIndexプロパティが設定されてコントロール配列になります。

今度は3つのコマンドボタンをコントロール配列にしたいので、さっき配置した3つのコマンドボタンは一度消して、コピーして貼り付ける方法でやってみてください。名前はMyButtonとしましょう。

コントロール配列の準備ができていればプログラムは簡単で、さっきと同じ事をするプログラムは次のようになります。

Private Sub Form_Load()

MyImage(1).Picture = LoadPicture("C:\hare.gif")    '晴の画像を読み込む

MyImage(2).Picture = LoadPicture("C:\ame.gif")    '雨の画像を読み込む

MyImage(3).Picture = LoadPicture("C:\yuki.gif")    '雪の画像を読み込む

End Sub

Private Sub MyButton_Click(Index As Integer)

Picture1.Picture = MyImage(Index).Picture

End Sub

以上で完成ですからずいぶんと短くてすむものです。

 

3.やや詳しい説明

 

コントロール配列は数字でコントロールを参照する方法です。数字はあらかじめIndexプロパティで設定したものが使われます。

たとえば、Indexプロパティが3で、名前がLabelであるコントロールには次のようにプログラムすることができます。


Label(3).Caption = "Hello!"
 

コントロール配列のすばらしい点は数字でコントロールを指定できる点です。つまり、変数が使えます。上の例は次のように書くこともできます。

K = 3

Label(K).Caption = "Hello!"

この2つはまったく同じ動作をします。下の例はIndexを変数でとっているので、場合に応じて指定するコントロールを変更することができる点で便利です。この他にループ処理と併用して次のようなこともできます。

For K = 1 To 10

Label(K).Caption = K & "個目のコントロール"

Next K

コントロール配列はこのようなループ処理でとりわけ威力を発揮することでしょう。

 

コントロール配列になっているコントロールはどれも名前は同じになります。Indexの重複は許されません。これらの性質からコントロール配列のイベントプロシージャはやや特殊になります。コントロール配列になっているコントロールはすべて同じイベントプロシージャを共用します。たとえば、MyCommandというコントロール配列があるとき、クリックイベントプロシージャはIndexの違いによらず必ず、

Private Sub MyCommand_Click(Index As Integer)

が呼び出されます。よくみると普通のクリックイベントプロシージャと違ってかっこの中に引数(パラメータ)が入っています。これが特徴です。

この引数を使ってどのIndexのMyCommandがクリックしたか知ることができます。この処理は例えば次のようになります。

Private Sub MyCommand_Click(Index As Integer)

MsgBox "インデックス " & Index & " のボタンがクリックされました。"

End Sub

「Index」という単語は引数に指定されているので宣言をしないで使うことができ、自動的にクリックされたMyCommandのIndexプロパティの値が格納されています。

 

4.コントロール配列の応用

 

以上で一通りコントロール配列の説明をしました。ここまで知っていればコントロール配列を活用して、短いコードで性能のいいプログラムを書くことができることでしょう。

ここからは簡単にこの他のコントロール配列の応用を紹介します。参考程度に読み流してください。

 

@コレクション

コントロール配列はコレクションです。(コレクションの説明はまだしていませんね。知らない人は気にしないで読むだけ読んどいてください)。そのため、短いコードで配列のすべての要素のアクセスできます。たとえば、次のコードはすべてのMyImageの表示非表示を切り替えます。

Dim o As Image

For Each o In MyImage

o.Visible = Not o.Visible

Next

この例は同様の処理をFor Nextで行った場合よりも高速で動作します。もちろんVisibleプロパティ以外の処理もできますから、わからない人もこのままコピーして使ってみてください。

A動的ロード

通常、コントロールは、デザイン時つまりプログラム時に配置するものですがコントロール配列になっているコントロールは実行時にも配置したり削除したりできます。(VB6ではコントロール配列になっていないコントロールも動的に追加できる)。

コントロール配列を動的に追加するにはLoadステートメントを使います。簡単な例では


Load MyImage(7)
 

のようにします。

次の例では、クリックするたびに新しいボタンができていきます。

このコードを実行するにはあらかじめフォームの上のほうにCommand1という名前でコマンドボタンを配置して、Indexプロパティを 0 にしておいてください。

Private Sub Command1_Click(Index As Integer)

Static K As Integer

K = K + 1

Load Command1(K)

Command1(K).Top = Command1(K-1).Top + Command1(K-1).Height

Command1(K).Visible = True

End Sub

注意すべき点はいくつかあります。Loadで追加されたコントロールのプロパティはすべてIndexが0であるコントロールと同じになります。(Index 0が存在しない場合には1、それもなければ2・・・・といった具合)。そのため、Loadされたコントロールは別のコントロールと同じ場所に配置されるために場所を動かすか何かしないと見えません。

さらに、VisibleプロパティだけはいつもFalseの状態でLoadされるので、表示したければ必ず十分でVisibleプロパティをTrueにする必要があります。

この方法を採用しようと思う人は同様のことがVisibleプロパティの操作によっても実現できることに注意してください。この方法を採用するメリットはメモリを動的に確保できる点、それとデザイン時にいくつもコントロールを並べる手間を省く点です。

B2次元配列

コントロール配列は常に1次元配列で、2次元配列にすることはできません。そこで、コントロールを2次元配列で使いたいと思ったら1次元配列を擬似的に2次元化する必要があります。

たとえば,4×5の2次元配列でコントロール配列を扱うには、Index1〜20のコントロール配列を用意して次の関数を組み込みます。(この例では4*5のうち、5の方は無視していますが問題なく動作します)。

Private Function Dc(Tate As Integer,Yoko As Integer)

Dc = (Tate - 1) * 4 + Yoko

End Function

これで、プログラム中で(2,3)の要素を参照したかったら、MyControl(Dc(2,3)のようにすればOKです。実際は1次元配列ですが、2次元配列の手軽さで使用することができます。関数の中で4を定数にすればさらに柔軟なプログラミングが可能です。

 

5.最後に

 

初級編もここまでくるとあんまり「初級」という感じはしませんね。ここまでの知識があれば相当なプログラムが作れるのではないかと思います。ここまでついてこれる方は是非中級編テクニック編もご覧ください。でも、初級講座もまだつづきますよ。