ExcelVBAゲームプログラミング?

初心者でもきっとできる!
Excelさえ持っていれば特別なソフトは不要!
すぐにでも始められる簡単ゲームプログラミング!
今すぐ始めよう!

サンプルやゲームのダウンロードができる別館も好評運営中です。
ご意見やご質問、ゲームの感想等は掲示板までお気軽に。是非、皆さんの声を聞かせてください。運営、開発の励みになります。



各種ダウンロードはコチラ ↓ 意見・感想・質問はコチラ ↓
影倉庫 Shadow warehouse サポート掲示板
ブログの全体像はコチラ ↓ リンクのページはコチラ ↓
サイトマップ 自分本位なリンク


スポンサーサイト

上記の広告は1ヶ月以上更新のないブログに表示されています。
新しい記事を書く事で広告が消せます。






Chapter.76 [ オブジェクトとコレクション ]

■コレクション

今回のテーマは『 コレクション 』です。

コレクションとは言っても、『超レアなトレーディングカードを持ってます』とか、『業物の骨董品を持ってます』とか、そういうコレクションじゃありません。

プログラミングでコレクションと言うと、上で書いたような、ものを収集することとは全く関係がありません。

VBAで言うところのコレクションとは、簡単にいうと『オブジェクトの集まり』のことを表します。オブジェクトの集まりと言われても中々イメージが湧かないかもしれませんが、きっと皆さんは既に、無意識のうちにコレクションを体験しているはずです。知らず知らずのうちに。

コレクションという概念を理解していると、オブジェクトに関する理解が深まります。コレクションを活用することによって便利に、そして簡単にプログラムが組める場面も出てきます。是非、この機会に習得してほしいと思います。

それから最初に書いておきますが、コレクションを理解するには、最低限のオブジェクトに関する理解は必要です。
いきなりここから始めるのではなく、あらかじめオブジェクトについても理解しておいてくださいね。オブジェクトについては以前の講座、(Chapter73Chapter74Chapter75)あたりを参照してください。


■知らずに使っているコレクション

先ほど、コレクションはオブジェクトの集まりであると書きました。皆さんはこれを言われて、すぐにコレクションが何であるか、想像がつきましたか?

多分、想像つかないと思います。

でも焦る必要はありません。わかってしまえば、何気に簡単です。
わかりやすく理解するために簡単な例を挙げて考えてみることにしましょう。

例えば、ワークシートのセルを考えてみてください。
以前にも何度かお話したように、ワークシート上のセルは、そのひとつひとつが独立したオブジェクトです。具体的には、セルひとつで、ひとつの Range オブジェクトですね。

つまり、ワークシートの中には、たくさんの『セル』というオブジェクトがひしめき合っているわけですね。
Excel97~2003までなら、ワークシートひとつに対して縦65536行×横256列のセルがあります。総勢16777216個のオブジェクトがひとかたまりになっているわけです。

これがいわゆるコレクションです。今回の場合は、Range オブジェクトの集合体なので、これを Range コレクションと呼びます。

皆さんは今まで、VBAを使って、セルに何かしらの操作を行ったことがあると思います。実は、そういった処理の全ては、Range コレクションにアクセスして行っていたのです。コレクションを意識したことは無いかもしれませんが、セルに何かしらの操作を行うこと自体が、実はコレクションを用いた処理の一環だったのです。


■それはまるで詰め合わせ

コレクションは、オブジェクトの集合体です。これについてはなんとなく理解できましたか?

ワークシート上のセルは、全てが Range コレクションの一員です。例えて言うならば、お歳暮なんかでよく来る『のり缶詰め合わせ』は、まさしく『のり缶』というオブジェクトのコレクションだと言えますね。

そして、コレクションを理解するうえで、もうひとつ重要なポイントがあります。

そのポイントとは、Excel で扱われるオブジェクトが階層構造になっているという点です。


先ほど登場した、 Range オブジェクトは、常にワークシートに存在するオブジェクトですね。ワークシートがなくて、セルだけがある、なんてことはないですもんね。

同じように、ワークシート( WorkSheet オブジェクト)は、常にワークブックに存在するオブジェクトです。Excelのブックという存在が無いところに、ワークシートが存在するわけがありません。

そしてさらに言うと、ワークブック( WorkBook オブジェクト)でさえ、Excel が無ければ存在できないオブジェクトですよね。Excelブックのファイルだけがあっても、それを開くことができる Excel 本体が無ければ意味がありません。

こうして考えてみると、コレクションとはいろいろなモノを詰め込んだ箱のようなものだと考えることができますね。

Excel 本体、つまりアプリケーションが一番大きな箱です。そして、その中には、様々な箱が詰め込まれています。

ある箱には、『 WorkBooks コレクション 』と書いてあります。これがブックオブジェクトのコレクションですね。Excel は同時にいくつものブックを開くことができます。ふたつでもみっつでも、同時に開いて編集することができます。同じオブジェクトの集まりですから、これも立派なコレクションなのです。

WorkBooks コレクションの箱を開けてみると、中にはひとつ、あるいは複数の『 WorkBook オブジェクト 』と書かれた箱が入っているというわけです。
続いて、この箱も開けてみます。すると、その中には『 WorkSheets コレクション 』と書かれた箱が入っています。

この箱を開けると、中には『 WorkSheet オブジェクト 』と書かれた箱が入っています。ワークシートがひとつしかないなら、箱はひとつでしょうが、複数のワークシートがあるなら、箱もたくさんあるはずですね。

『 WorkSheet オブジェクト 』と書かれた箱も開けてみます。

今度は何が入っているのでしょうか。

ここまでくると、なんとなく想像がつきますよね。

中には、『 Range コレクション 』と書かれた箱が入っています。
そして、さらに箱を開けると、当然『 Range オブジェクト 』と書かれた箱が出てきます。これも開けてみると、まだまだ箱は出てきます。大変ですね。いつになったら終わるんでしょうか……。


このように、オブジェクトは階層構造になっています。一番大きな箱は、アプリケーションそのもの、つまり Excel 本体です。そして、その中には、オブジェクトやコレクションがたくさん詰まっているのです。

『のり缶詰め合わせ』を例に考えるのもいいでしょう。

のり缶詰め合わせは、広い意味で言えば、『お歳暮コレクション』の一員ですよね。お歳暮は、多分『商品コレクション』の一員か何かでしょう。

詰め合わせの中の『のり缶オブジェクト』の下には、『味のりコレクション』とか、『浅草のりコレクション』とかがあるんでしょう。多分。

最終的には、『のりオブジェクト』まで辿り着けるんではないでしょうかね。いや、『のりのカス オブジェクト』かな、最後は……。
どうでもいいですね。すいません、くだらない例えでした。


■オブジェクトやコレクションの種類

上記の例では、Application、つまり Excel 本体の箱を開けると WorkBooks コレクションが出てくると書きましたが、Application 直下のコレクションやオブジェクトは、なにも WorkBooks コレクションだけではありません。これ以外にも、非常にたくさんのオブジェクトやコレクションが含まれています。

興味のある人は、VBAのヘルプで、『Microsoft Office Excel オブジェクト モデル』という項目を見てみるといいでしょう。ここでは全てのオブジェクトやコレクションの階層構造を見ることができます。

普段は中々目にすることが無いようなオブジェクトがたくさん出てきて、ちょっと新鮮な気分になれると思います。

そして、先ほども書いたように、オブジェクトやコレクションは階層構造になっています。大きな箱の中に、ちょっと小さな箱があり、その中にはさらに小さな箱が入っているのです。

当講座ではおなじみのユーザーフォームも、階層構造をキチンと持っています。

『ユーザーフォーム』という大きな箱があり、その下には『コントロールのコレクション』があります。コントロールコレクションの中には、コマンドボタンやイメージコントロールなどの各種コントロールが入ることになります。

ここで出てきた『階層構造』という概念を正しく理解できていないと、間違って次のような記述をしてしまい、エラーが起きたりします。

Workbooks(1).Range("A1").Select

このコードは、『ワークブック ⇒ セル』という順序で指定して、処理を行おうとしています。本当なら、セルを指定する前に『ワークシート』を挟んでおかなくてはいけないのですね。
もしこのまま実行してしまうと、次のようなエラーが起こります。

実行時エラー'438':

オブジェクトは、このプロパティまたはメソッドをサポートしていません。

このようなエラーが起こる場合、大抵はオブジェクトの階層構造が正しく指定できていないことが多いです。今回の場合、ワークブックのコレクションから、直接セルを参照することはできないのでエラーになっているのですね。

正しく記述し直すと、次のようになります。

Workbooks(1).WorkSheets(1).Range("A1").Select

オブジェクトやコレクションの階層構造が、正しく指定できているので、これならエラーは発生しません。


■まとめ

さて、コレクションについて、なんとなく理解できたでしょうか。

いまさらですが、のり缶の例えは非常にわかりにくかったような気がしてなりません。理解できなかった方、すいません。

しかし、オブジェクトやコレクションは、いろんなものに例えながら考えるのが、理解を深める近道だと私は考えています。オブジェクトの話を以前したときにも、オブジェクトを人間に例えて考えましたよね。コレクションも、これと同じように考えると、結構簡単です。

『人間』には、肌の黒い人もいるし、白い人もいる。しゃべる言葉や文化もいろいろあります。でも、大分類で言えば、皆同じ人間ですよね。ですから我々は皆、『人間コレクション』の一員なのです。

『人間コレクション』は、たくさんの『人間オブジェクト』を内包しています。

『人間オブジェクト』は、『肌の色プロパティ』や、『しゃべる言葉プロパティ』、『歩くメソッド』などを持っていて、それぞれ全く異なる個性を持つことができるのですね。

オブジェクトやコレクション、そしてプロパティやメソッドなど、少し難しい話がここ何回か続いています。途中でわけがわからなくなった人もいるかもしれませんね。

しかし、焦ってないがしろにしてしまうより、気長にゆっくり、理解できるまでがんばってみてください。一度に理解することができなくても、それが脱落を表すわけではありません。また今度、気の向いたときに考えてみて理解できればそれでいいと思います。

私の言葉が、皆さんの理解の一助となればいいのですが……。



■格言

コレクションはオブジェクトの集合体
コレクションやオブジェクトは
階層構造になっている


ここが理解できれば、次回の内容もスムーズにいけます。がんばってください。


スポンサーサイト






Chapter.77 [ 特殊な繰り返し:For Each ]

■奥の深い繰り返し

皆さんが『繰り返し処理』と言われて思い浮かべるのは何でしょうか?

For 文での繰り返し処理でしょうか、それとも、Do~Loop 文での繰り返し処理でしょうか。

繰り返し処理は、どういった処理を実現したいのかによって、For 文を用いるのか Do~Loop 文を用いるのかが変わってきます。これは以前の講座でも何度か解説しましたね。

For 文は、繰り返し処理する回数があらかじめ決まっている場合などに適しており、配列を処理する際などには必須のテクニックですね。
これに対し Do~Loop 文は、繰り返し処理する回数が不確定な場合などに適しています。ゲームなどの同期処理を行ううえでは、この Do~Loop 文を使うシーンが多く登場します。

それぞれの特性をよく理解し、状況に応じて使い分けるのが最も優れた処理といえます。しかし、繰り返し処理は、なにも先ほどの2種類しか無いというわけではありません。
実は、今回紹介する For 文のもうひとつの文法を駆使すると、さらに高度な繰り返し処理を実現することが可能になります。

更なるレベルアップを目指して、今回は『 For Each 文 』をやってみることにしましょう。


■どうやって使うの?

さて、今回のテーマである『 For Each 文 』とは、一体なんなのでしょうか。そして、通常の For 文での繰り返し処理と、一体何が違うのでしょうか。

For Each 文を用いる場合は、繰り返し処理の対象となるものが限定されます。具体的には、『配列』、もしくは『コレクション』が対象となります。
こんなふうに言われても、なかなかイメージしにくいですね。

例えば、次のようなケースを考えてみてください。

ユーザーフォーム上に、複数のコントロールが配置されている。
それぞれのコントロールは種類が異なる。
これらのコントロール全てを順番に処理して、キャプションを統一する。


440.gif


さて、上の画像のようなユーザーフォームにおいて、全てのコントロールを順番に処理するにはどのようにプログラムを記述すればいいのでしょうか。
先ほども書いたように、For Each 文では、配列か、またはコレクションに対して繰り返し処理を行います。

ユーザーフォーム上に配置されたコントロールは、全て『 Controls コレクション 』の一員です。同じユーザーフォーム上に配置されているなら、例え種類の異なるコントロールであっても、この Controls コレクションに必ず含まれます。
この Controls コレクションを For Each 文を用いて繰り返し処理することができれば、全てのコントロールのキャプションをまとめて変更することができます。

さて、それでは実際にやってみることにしましょう。

Sub For_Each_Next()

    Dim C As MSForms.Control '①
    
    For Each C In UserForm1.Controls '②
        C.Caption = "現在の時刻⇒ " & Time '③
    Next
        
End Sub

一見すると非常にわかりにくいと思います。ひとつひとつ順番に見ていきます。

まずは、①の部分です。
ここでは、For Each 文で繰り返し処理するための変数を宣言しています。
思い出してみてください、。通常の For 文でも、カウンターとなる変数をあらかじめ宣言していましたよね。For Each 文の場合にも、通常のFor 文と同じように、繰り返し処理するために変数が必要となります。

ただし、ここで注意しなくてはならないのが、その変数のです。

先ほどの①の部分では、変数の型に『 MSForms.Control 』と指定されています。これは『ユーザーフォーム上に配置されたコントロール』を表す変数の型です。

今回のサンプルコードでは、ユーザーフォーム上のコントロールを順番に処理します。For Each 文では、繰り返し処理する対象となるモノを変数の型としてあらかじめ宣言するのですね。

例えば、今回はユーザーフォーム上のコントロールが対象ですが、ワークシートのセルを対象にして For Each 文を使う場合には、次のように変数を宣言しておく必要があります。

Dim R As Range

ワークシートのセルは、Range オブジェクトでしたね。もしも For Each 文で繰り返し処理する対象がセルとなる場合には、これに応じた変数の型として Range オブジェクト型の変数を宣言しておくわけです。

さて、こうして①の部分で、変数の宣言は完了しました。
しかし、この変数は、まだ宣言されただけなので、中身は何も入っていない状態です。これはオブジェクトに関して解説した講座でも説明しましたね。オブジェクトが入る変数には、宣言された段階では何も入っていません。 Nothing の状態です。

今回で言うと、変数 C がこれにあたりますね。①の部分では、宣言が行われただけなので、まだ中身には何も入っていません。

そして②です。ここが For Each 文の肝です。

For Each C In UserForm1.Controls

少しわかりにくいと思いますが、色分けされているのを参考にして考えてみてください。

まず文法としては、For Each に半角スペースを空けて、先ほど宣言した変数を記述します。今回の場合は変数 C ですね。
次に、また半角スペースを空けて、『 In 』、さらに半角スペースを空けて、繰り返しの対象となるコレクションや配列を記述します。

今回のサンプルは、『ユーザーフォーム上のコントロールを順番に処理』でしたよね。ですから、黄色い文字で表示されている部分(対象となるコレクション)が、『 UserForm1.Controls 』となっているのです。
つまり For Each 文の構造としては、次のようになっています。

For Each 変数 In 対象となるコレクションや配列

先ほども書きましたが、注意するべきなのは『変数』と『対象となるコレクションや配列』との関係です。
ユーザーフォーム上のコントロールを順番に処理するのに、変数が Range 型で宣言されていたら、うまくいくはずがありませんね。かならず変数と対象となるコレクションの間に関連性が無くてはいけません。

どうしても関連性がうまく取れない(型がわからないなど)の事態に遭遇したときは、Variant 型の変数を使うという手もあります。ご存知の通り、Variant 型は何でも入ってしまう便利な型です。どうしても変数の型が特定できない、うまくいかないときには応急処置として使ってしまうこともできます。

さぁ、②までうまくいけば、あとはもう簡単です。

次の③の部分では、変数 C に対して処理をしていますね。変数 C はこのとき、コレクションの各要素を順番に格納していくオブジェクト変数です。

C.Caption = "現在の時刻⇒ " & Time

先ほどの②まで正しく処理できていると、変数 C の中には、対象となるコレクションの要素がひとつずつ順番に入ります。例えば3つの要素を持つコレクションが処理の対象となる場合は、For Each 文が3回繰り返し処理されるはずです。

今回のサンプルでは、対象となるコレクションが11個の要素を持っています。これは先ほど出てきた画像を見るとわかりますね。

440.gif

ラベル3個、チェックボックス3個、フレームが2個、オプションボタンが2個、コマンドボタンが1個の合計11個のコントロールがあります。

今回のFor Each 文は、11回の繰り返し処理が行われ、順番に各コントロールが処理されます。コードを実行すると、各コントロールのキャプションが一気に変更されます。

441.gif


■まとめ

For Each 文は構造が少し複雑な感じがしますので、そういった意味で理解しにくいと思います。ただ、オブジェクトやコレクションについてある程度理解できていれば、ゆっくり考えれば大丈夫なはずです。

大事なことは、自分が繰り返し処理したい対象が、なんというコレクションなのか、そして、そのコレクションを正しく処理するためには、どのような型で変数を宣言しておかなくてはいけないのか、をハッキリさせておくことです。

どうしても変数の型がわからないときは、とりあえず Variant 型を使って動作確認してみるのもいいでしょうし、焦らず諦めず、探求していくことが大事です。


また、For Each 文で処理できるのはコレクションだけではなく、配列を対象とすることも可能です。この場合にも、変数と対象とるな配列のデータ型が一致している必要があるので、その点は十分に注意しましょう。


下記のリンクから、今回解説に使用したファイルをそのままサンプルとしてダウンロードできます。参考にしてみてください。

サンプルダウンロード ⇒ コチラよりダウンロードできます。(別館)



■格言

For Each 文で繰り返し処理する
対象となるのは配列またはコレクション


ちょっと難しいですが、マスターすると結構便利ですよ。








Chapter.78 [ エラー処理 ]

■永遠のライバル

プログラマーの永遠のライバル、それはバグとエラーでしょう。

どのようなプログラムであっても、絶対に避けては通れない、それがバグとエラーに関する対処です。以前、バグに関しては解説しましたが、まだエラーに関する解説を行っていませんでした。今回は、エラー処理について考えてみることにしましょう。

そもそも、エラーって一体なんなんでしょうか。そして、エラーにも色んな種類があるものなんでしょうか。その辺りから考えていきましょう。


■大分類でのエラーの種類

エラーには大きく分けて2種類のエラーがあります。ひとつは『コンパイルエラー』と呼ばれるエラー、そしてもうひとつが『実行時エラー』です。

どちらも、VBAでプログラミングをしていると、頻繁にお目にかかると思います。

コンパイルエラーは、その名の通りコードの文法が間違っているが為に発生するエラーです。VBAはインタプリタ言語と呼ばれるプログラミング言語の一種です。インタプリタ言語では、コードを記述しながら、常にバックグラウンドでコードをコンパイルして、間違いが無いかどうかを常時調べてくれます。

例えば、間違った記述をすると、次のような画面になり、コードが赤くなってしまいます。

450.gif

これがコンパイルエラーですね。
文法自体が間違っているため、正しくコンパイルができず、エラーとなってしまいます。
このような文法の間違いを、そのままほったらかしにする人はまずいないと思いますが、当然このままではコードを実行させることはできません。

コンパイルエラーに関しては、目立ちやすいことや、原因がわかりやすいこともあって、大抵はすぐに修正することができます。やっかいなのはもうひとつのエラー、『実行時エラー』のほうです。

実行時エラーは、文法上の間違いが無くても発生するため、コンパイルエラーに比べると非常にやっかいです。
また、原因がわからないことも多く、大抵はコチラのエラーに悩まされることになります。

例えば、実行時エラーの起きる状況としては、次のようなケースがあります。

存在しないものを参照しようとしたとき


451.gif


これは、ワークシートやセルを用いて処理している場合によく起こる実行時エラーです。
ワークシートが3つしかないのに、4つめのシートを操作しようとすれば、当然実行時エラーが発生します。
また、ありえないセルを操作しようとしたりした場合にも、やはり同じようなエラーが発生します。例えば、次のコードは、コンパイルエラーは発生しませんが、絶対に実行時エラーが発生します。

MsgBox Cells(0, 0).Value

ワークシートのセルは、『 Cells(1, 1) 』から始まります。0 の座標というのは存在しないので、確実に実行時エラーが発生します。また、最大で『 Cells(65536, 256) 』までしかセルが存在しないので(Excel2003などの場合)、それ以上の数値を指定してセルを参照した場合にも、実行時エラーが起こります。

ループなどで変数を用いてセルを参照する場合などは、こういった間違いが起こりやすいと思います。使われている変数の値が小さすぎないか、あるいは大きすぎないか、注意するようにしましょう。


どうですか? コンパイルエラーと実行時エラーの違いが理解できましたか?


■実行時エラーとエラートラップ

さて、エラーには大きく分けて2種類あるということがわかりました。
しかし、コンパイルエラーはいいとして、実行時エラーにはやっかいな問題があることもわかりましたね。

実行時エラーは、実行してみないとわからないことが多いうえ、実行される環境の違いによる影響も大きく、一見して原因を特定できないこともよくあります。

しかし、あらかじめエラーが起こる可能性を開発段階で予測できる場合は、これに対して先手を打っておくことが可能です。
『もし、エラーが発生してしまったら……』という具合に、まるで If 文と同じような感覚で、エラーを回避したり適切に処置を施したりできるのです。

しかも、エラーが起きた場合に、どのように対処するのかを細かく指定することができます。
例えば、『エラーが起きた場合だけ特別な処理をする』とか、『エラーが起きた場合はそれを無視して先に進む』とか、『エラーが起きた場合には対処をしたうえでもう一度やりなおす』とか、いろいろできます。

一般的に、このようにエラーが起きることを想定して、あらかじめ何らかの手を打っておくことを『エラートラップ』といいます。エラーが発生してしまった場合の処理を適切に記述しておくことで、プログラムの実行が止まってしまうことの無いようにしておくわけです。

今回は、前回紹介した For Each 文を使って、エラートラップについて考えてみましょう。


■エラーを無視して進む

前回紹介した、For Each 文の処理では、ユーザーフォーム上に配置された、種類の異なるコントロールを順番に処理して、それぞれのキャプションを統一していました。

しかし、考えてみると、これはどんなケースでも使えるコードではありません。

なぜなら、キャプション( Caption プロパティ)は、どのコントロールにも必ず備わっているとは限りません。
イメージコントロールのように、キャプションが存在しないコントロールも中にはあるのです。

もし、前回のコードを、イメージコントロールの配置されているユーザーフォームでそのまま使ってしまうと、確実にエラーが発生してしまいます。
こんなときに、エラートラップが必要になります。

エラーをトラップするには、いくつかの方法があります。
今回はまず手始めに、エラーが発生してしまった場合には、それを無視して先に進むプログラムをやってみましょう。

おさらいも兼ねて、前回のコードをまずは見てみます。

Sub For_Each_Next()

    Dim C As MSForms.Control
    
    For Each C In UserForm1.Controls
        C.Caption = "現在の時刻⇒ " & Time
    Next
        
End Sub

このコードは、ユーザーフォーム( UserForm1 )上に配置されている全てのコントロールに対して、連続して処理するコードです。

For Each 文の処理の中で、キャプションを変更している部分がありますね。
C.Caption = "現在の時刻⇒ " & Time 』の部分です。ここが、エラーが発生する可能性のあるポイントになります。

もしも、ユーザーフォーム上に、Caption プロパティを持たないコントロールが配置されていた場合には、エラーが発生してしまうことになるので、これをトラップしておき、エラーの発生に対処します。

それが次のコードです。

Sub For_Each_Next()

    Dim C As MSForms.Control

On Error Resume Next

    For Each C In UserForm1.Controls
        C.Caption = "現在の時刻⇒ " & Time
    Next
        
End Sub

緑の字で表示されている一文、これこそがエラーに対処するためのコードです。

このように記述しておくと、それ以降の部分でエラーが発生しても、コードの実行が止まってしまうことはありません。
VBAに対して、『これ以降はエラーが起きても気にしないで進みなさい』と命令するわけです。

このようにコードが記述されていれば、例えユーザーフォーム上にイメージコントロールやテキストボックスなどの、Caption プロパティを持たないコントロールが配置されていても、エラーが発生することはありません。


On Error Resume Next 』の細かい解説は、次回にまとめて行うつもりです。今回の講座では、参考までにコードを載せましたが、あまりよくわからなくても大丈夫です。

今回の講座で大切なことは、『エラーには大きく分けて2種類ある』ということと、『どうしてもエラーが発生する場合には先手を打っておくことができる』ということです。

コンパイルエラーと実行時エラーは、その意味が根本的に違います。まずはそれをしっかり理解しましょう。

そして、実行時エラーに関しては、どうしても発生してしまうケースがあり、開発段階でそれがわかっている場合には、あらかじめ対処法を記述しておくことができるのです。
具体的にどのような対処法があるのかは、次回詳しく解説します。今回紹介したコードの詳細も、併せて解説する予定ですのでお楽しみに。



■格言

エラーには2種類ある
コンパイルエラーと実行時エラー
エラーが予測できるなら先手を打てる


ある程度大きなプログラムでは必須のテクニックになります。
ちょっと難しいかもしれませんが、がんばってください。









Chapter.79 [ On Error と GoTo文 ]

■エラーの可能性

前回、エラー処理のひとつの例として、エラーが発生してもそれを無視して実行を続ける方法を解説しました。

ゲームの処理に限ったことではありませんが、エラーが発生してプログラムが止まってしまうことは望ましくありません。しかし、エラーが絶対に発生しないプログラムというのは、実際ほとんど無いというのが現実です。

これは、プログラムの実行される環境による影響や、ユーザーの不適切な操作など、プログラムにとっての危険因子がパソコンにはたくさんあるからです。

だとすれば、我々開発者側がやらなくてはならないこととはなんでしょうか。

それは、エラーの発生を予測し、あらかじめ対応策を講じておくということに尽きます。こんなエラーが起きる可能性があるな、と予測できるなら、それに対して何らかの対処をしておく必要があるのです。

今回はエラー処理に関する具体的な内容を解説していきます。じっくりと取り組み、確実にひとつひとつ理解していきましょう。


■コードが実行される順序

VBAでは、原則として記述されたコードが上から順番に実行されていきます。これは今更言わなくてもイメージできると思います。

しかし、VBAには『コードは上から実行』という原則を、あえて破ってしまう記述方法が用意されています。それが『 GoTo 文 』です。

GoTo 文を用いると、同じプロシージャの中であれば、どこでも好きなところにコードの実行を移行することができます。例えば次のような例を見てみましょう。

Sub GoTo_Test()

    Dim L As Long
    
    L = Int(Rnd * 10)
    
    If L < 5 Then
        
        GoTo 1 '①
    
    End If
    
    Exit Sub '②
    
1        '③

    MsgBox "取得した乱数は5より小さい"
    
End Sub

このコードを実行すると、一定の確率でメッセージが表示されます。どのような仕組みになっているのか、なんとなくコードから想像がつくでしょうか。

まず、一番最初に、変数 L に乱数を取得していますね。

L = Int(Rnd * 10)

この一文によって、変数 L には、0~9までのいずれかの整数が入ります。このコードに関する詳しい説明は乱数の解説でやりましたね(Chapter12を参照)。

そして次に、この取得した乱数の値によって、 If 文で処理が分岐します。

もしも、取得した乱数が 5 よりも小さい値だった場合には、①の部分に処理が進みます。

①には、次のように書かれています。

GoTo 1

GoTo 』に続けて、『 1 』と記述されています。ここで登場した『 1 』は、『 行番号 』と呼ばれます。

このように GoTo 文に続けて行番号を指定すると、強制的に指定された行にコードの実行が移ります。今回の場合は③の部分にもやはり『 1 』と書かれていますね。この③のところにある 1 が、行番号です。

ですから、今回のコードは次のような感じで処理されます。

変数 L に乱数を取得
    ▼
もし変数 L の値が 5 よりも小さい値だった場合は
If 文による分岐処理で GoTo 文が実行される
    ▼
GoTo 文の効果で行番号 1 へコードの実行が移る
    ▼
行番号 1 以降のコードが実行される(メッセージを表示)

行番号をあらかじめ指定しておけば、強制的にコードの実行箇所を移行させることができるわけですね。

一見すると非常に便利な GoTo 文ですが、注意すべきこともあります。

基本的に行番号は、それ単体でコードの実行に対して何か影響を与えることはありません。あくまでも GoTo 文とセットで意味をなすものです。ですから、②の部分で示したように、行番号以降のコードが必要ない場合は、明示的にプロシージャを終了するなり、何かの対処をしておく必要があります。

もし仮に次のようにコードを記述してしまうと……

Sub GoTo_Test()

    Dim L As Long
    
    L = Int(Rnd * 10)
    
    If L < 5 Then
        
        GoTo 1
    
    End If

1

    MsgBox "取得した乱数は5より小さい"
    
End Sub

これだと、取得した乱数がどんな数値であっても、絶対にメッセージが表示されます。行番号は、それ単体では何の意味も持たないのです。注意しましょう。


■行ラベル

行番号の変わりに、行ラベルを使うこともできます。

行ラベルは、行番号に比べて、人間から見たときに意味がわかりやすいです。先ほどのコードを、行ラベルを使って書き直してみます。それがこれ。

    Dim L As Long
    
    L = Int(Rnd * 10)
    
    If L < 5 Then
        
        GoTo JAMP
    
    End If
    
    Exit Sub
    
JAMP:

    MsgBox "取得した乱数は5より小さい"
    
End Sub

簡単ですね。数字が文字に変わっただけです。

ただ、行ラベルを使う場合は、行ラベルの末尾にコロン『これ ⇒ : 』をつけることになっています。使い方は行番号と全く同じです。

そして、行番号を使うにしても、行ラベルを使うにしても、GoTo 文に関して絶対に理解しておくべきことがあります。

それは、『できるだけ使うな』です。
さんざん説明するだけしといてこんなこと言うのもなんですが、行番号や行ラベルを使うと、コードのどこからでも、好きなときに好きな場所へ強制的にコードの実行を移すことができます。

これは非常に便利に思えますが、一般に、GoTo 文はできるだけ使わないことが推奨されます。なぜなら、コードの全体像がつかみにくくなる上、デバッグが難しくなるからです。

バグが起きて修正しようとしているときに、コードの実行があっちへ行ったりこっちへ行ったりすると、いったいどこがバグの原因なのか究明が難しくなります。あとから自分でコードを見直した際にも、何をやろうとしているのかわからなくなることが出てくるでしょう。

他人がコードを見た場合にも、同様のことが起こります。そしてプログラムが大きくなればなるほど、構造を把握するのが難しくなります。十分に注意するようにしましょう。


■やっとエラー処理

さて、ちょっと長くなりますが、一気に行きます。

先ほど登場した GoTo 文は、任意の場所に、自由にコードの実行を移すことができます。ここまでは理解できましたね。

そして、なんとなくこの仕組みが、エラー処理に使えたら便利そうな気がしませんか?

エラーが発生したら、そのときだけはこっちのコードを実行させて……という具合に処理できれば、エラーが発生した場合だけに限定して、特別な処理を行うことができますね。

これを実現するために使われるのが、前回も登場した、『 On Error 』です。

On Error は、エラーが発生したことを検知して特殊な処理を行いたいときに使います。前回の講座では、エラーが発生しても、それを無視してコードを実行させる方法を載せました。それがこれ。

On Error Resume Next

On Error が記述された行より先では、エラーが発生すると、それを検知することができます。

そして、On Error と、それに続くキーワード(便宜上キーワードとしますが、正確にはステートメント)の指定の仕方によって、エラーが発生したときにどのように対処するのかを決めることができます。

『 On Error + キーワード 』 で、エラーが起きたときの対処法を決めることができる


先ほど登場した『 Resume Next 』も、キーワードのひとつです。
そして、『 Resume Next 』は、『続きをそのまま実行する』という意味なのです。

このキーワードには、他にも次のようなものがあります。

キーワード意味
  On Error GoTo 行番号  指定された行番号へ移動
  On Error GoTo 行ラベル  指定された行ラベルの行へ移動
  On Error GoTo 0  エラーの検知をやめる
  On Error Resume Next  エラーを無視する


GoTo 文の使い方は先ほど説明しましたよね。エラー処理に用いる場合にも全く同じ要領で使うことができます。あらかじめ行番号や行ラベルを用意しておけば、エラーが発生した場合だけ、任意の場所へコードの実行を移行することができるわけです。

例えば、次のようなコードを実行すると、約50%の確立で、エラーが発生してメッセージが出ます。

Sub Error_Test()

    Dim L As Long
    
    L = Int(Rnd * 2) '①
    
On Error GoTo ERROR_HANDLE

    L = 10 / L '②
    
    Exit Sub '③
    
ERROR_HANDLE:

    MsgBox "0で割り算することはできません"
    
End Sub

数学のお約束ですが、0 で割り算をすることはできません。これはVBAでも同様で、もしそのような計算を行おうとするとエラーが発生します。

①の部分で、乱数を取得して変数に入れていますね。このとき、乱数の範囲は 0 か 1 のいずれかになるので、約半分の確立で、変数 L には 0 が入ります。

そして、②の部分で割り算をしようとしたとき、もしも変数 L の中身が 0 だった場合には、先ほども書いたように、0 では割り算ができないのがお約束ですからエラーが発生することになります。

今回の場合は、行ラベルを使って、エラーが起きた場合に移動するべきコードを指定しています。

そして注意点として押さえておかなくてはいけないのが、③で示しているように、エラーが発生しなかった場合には、エラー処理にコードの実行が移らないようにしておくことです。
もし Exit Sub を記述していなかった場合には、エラーが発生したかどうかに関わらず、絶対にメッセージが出るようになってしまいます。このようなエラーが発生しなかった場合にプロシージャを終了させる仕組みは、エラー処理における基本なので、忘れないようにしましょう。


■最後に補足

先ほど、 On Error に続くキーワードの一覧の中に、次のようなものがありましたね。

GoTo 0 …… エラーの検知をやめる

エラー処理を仕込んであるコードで、ここから先はエラーが起きるはずがない、とわかっている場合には、エラー処理を行わないようにしておきたい場合があります。

例えば、プログラムの構造上、ここまでは On Error Resume Next でエラーを無視しておきたいが、ある一定の箇所から先は、エラーが起きたらそれを無視してもらっては困る……、といった場合ですね。

このような場合には、 On Error GoTo 0 を使って、今までのエラー処理をリセットすることができます。このような記述が行われたあとでは、今まで有効になっていたいかなる On Error 文も全て無効化します。
開発段階で、様々なテストを行う際には、このような記述を有効に活用することで、事前にエラーが起きていないかどうかをチェックすることができるのです。


さて、今回はかなり長くなってしまいました。いきなりたくさんの情報をぶつけられて困惑している方もいらっしゃるかもしれません。

ただ、何度も講座内で書いてますが、焦りは禁物です。ひとつひとつ確実に身につけていきましょう。

GoTo 文は、できる限りそれ単体で使うのはやめましょう。これは、コードの可読性(読みやすさ、わかりやすさ)が失われることになるからです。
ただし、エラー処理の一環として使用する分には、使い方さえ間違っていなければ問題ないでしょう。あくまでもわかりやすさを重視して考え、無駄なコードの移動が起こらないように気をつけましょう。



■格言

GoTo 文を使ってコードを移行
On Error + キーワード で、エラーに対処


使い方というより、使い道が重要です。








Chapter.80 [ Resumeステートメント ]

■エラー処理の仕上げへ

さて、本講座もいよいよ80回目を迎えました。

これもひとえに、ご覧になってくださっている皆さんや、応援してくださる皆さんのおかげです。本当にありがとうございます。

今回は、エラー処理の最後の仕上げとして、Resume ステートメントについてやりたいと思います。

前回、前々回と、エラー処理に関することを基本から解説しました。今回の Resume ステートメントをマスターすれば、エラーに関してはほぼ大丈夫でしょう。

Resume ステートメントは、エラーが発生した際の対処に柔軟性を持たせてくれます。今までは一方通行なエラー対処法しかできませんでしたが、Resume ステートメントを活用することによって、再帰的に、エラーに対処することができるようになります。

頻繁に使う機能ということではないと思いますが、Resume ステートメントの使い方を知っていると便利な場面が必ずあります。ゆっくりで構いません。焦らず習得を目指してください。


■2種類ある Resume

以前の講座で、次のような記述について解説しましたね。

On Error Resume Next

順番に読み進めてきている方なら、今更解説の必要はないでしょう。
上記のコードは、エラーが発生した際に、そのエラーを無視するように設定するコードですね。

この一文をよく見てみると、その中に『 Resume 』という言葉が含まれています。しかし、今回解説する Resume ステートメントと、先ほど出てきた Resume は全くの別物です。
スペルは同じですが、違うものなので混同しないように気をつけてください。

それでは Resume ステートメントって何? ということですが、まずはこの英単語を、素直に直訳してみましょう。Resume を直訳すると『再開する』とか『再び始める』という意味になります。Resume ステートメントは、まさにこの単語の意味そのままの動作を実現させます。


■それで、どうやって使うの?

それでは、具体的な使い方を見てみましょう。

今回まずは、コードから見てもらうことにします。

Sub ResumeTest()

On Error GoTo ERR_HND

    Worksheets(5).Name = "5番目のシート" '①
    
    Exit Sub
    
ERR_HND:

    Worksheets.Add '②
    
    Resume '③
    
End Sub

このコードは、ワークシートの『シート名』を変更するコードです。

まず、プログラムが開始されるとすぐに、エラーをトラップするために、『 On Error GoTo ERR_HND 』が出てきますね。
これ以降、もしもエラーが発生すると、ERR_HND: と書かれている部分にコードが移ります。ここまではいいですね。

そして、①の部分を見てください。

ここでは、ワークシートの名前を変更するコードが書かれています。5番目のワークシートの名前を、『5番目のシート』という名前に変更しようとしています。

しかし、考えてみてください。もしも、ワークシートの5番目が存在しなかったらどうなるでしょう。普通は Excel のワークシートの規定値は3つに設定されていることが多いです。新しくブックを作成すると、ワークシートが3つあるのが普通ですね。

存在しないワークシートに名前をつけようとすれば……、これは当然エラーが発生します。

エラーが発生すると、先ほど設定した『 On Error GoTo ERR_HND 』の効果が働いて、コードの実行が行ラベルの部分に移ります。

そして、そこで②です。

②では、ワークシートを新しく追加しています。

Worksheets.Add

Add メソッドは、新しくワークシートを追加する機能を持っています。ですから、エラーが発生した場合にはこの部分にコードの実行が移り、新しくワークシートが追加されるわけです。

ワークシートがひとつしかない場合には、ワークシートがふたつになります。
ワークシートがふたつしかない場合には、みっつになりますね。

そして、その次に登場するのが、今回の肝、Resume ステートメントです。緑の文字で書かれている、③で示した部分ですね。

Resume ステートメントにコードの実行が差し掛かると、エラーが発生した場所にコードの実行が戻ります。

エラーが発生した場所、なので、今回で言うと①の部分にコードの実行が戻るのです。

つまり、エラーが発生してしまったところを、もう一度やり直すことができるんですね。これは便利です。

今回のコードでは、最初の段階でワークシートがたったひとつしかなくても、全く問題ありません。なぜなら、Resume ステートメントが機能することによって、『5番目のシートの名前を変更する』という目的を達成するまで、新しくシートを追加し続けるからです。

ワークシートの数が5つに満たないうちは、エラーが発生し続けますよね。それでも、エラー処理の中でResume ステートメントが機能することによって、何度でもワークシートを追加し続けるので、いつかは必ず5番目のシートの名前を変更することができるのです。


■おまけ:Err オブジェクト

さて、最後になりますが、ちょっとしたおまけとして、Err オブジェクトについて簡単に解説しておきます。

Err オブジェクトは、エラーの原因を特定したいときに非常に便利な機能を持っています。

VBAのコードの実行中に、なんらかのエラーが発生すると、次のように警告メッセージが出てきますね。きっと、しょっちゅう顔を合わせている人もいるでしょう。

460.gif

VBAで発生するエラーには、『エラー番号』と、どのようなエラーかを表す『エラーの内容』が必ず存在します。

エラー番号 11 ⇒ 『0で除算しました』

エラー番号 380 ⇒ 『プロパティの値が不正です』

エラー番号 440 ⇒ 『オートメーションエラーです』

このエラー番号と、エラーの内容は、後から調べることができます。その際に活躍するのが Err オブジェクトです。

エラーが発生すると、VBAはエラー番号とエラーの内容を、Err オブジェクトに自動的に格納します。

そして、情報が格納された Err オブジェクトへアクセスすることで、直近に起こったエラーの番号と内容を調べることができます。

Err.Number ⇒ エラー番号
Err.Description ⇒ エラーの内容

Err オブジェクトを有効に活用すると、エラーがなぜ発生したのかを調べ、エラーの種類によって処理を分岐させたりすることができます。

このエラーが起きたときはこの処理を、別のエラーのときはこちらの処理を、といった使い分けができるのですね。
あまり使うことは無いかもしれませんが、覚えておくといいでしょう。



■格言

Resume ステートメントで再起処理
Err オブジェクトを活用して
エラー番号やエラーの内容を調べる


これでもう、エラーは恐くないです……よね?









Chapter.81 [ バイトとビット ]

■低レベル・高レベル

さて、今回は少し難しい内容に挑戦したいと思っています。

こんなことを冒頭から書いてしまうと、少しびびってしまいますね。でも、これからもっと高度な処理を行っていこうと思ったら、どうしても必要になってくる部分なので、がんばって習得していただきたいと思います。

そんなわけで今回のテーマは『バイト』と『ビット』についてです。

C言語などでは、バイトやビットに関しての知識がとても重要な意味を持ちます。ある程度、バイトやビットについて理解していないと、比較的簡単なプログラムですら組むことができません。
これは、ひとことで言ってしまえば、C言語が比較的低レベルなプログラムを組める言語だから、ということになるでしょうか。ちょっとわかりにくいですね。

前にもどこかで書きましたが、プログラミング言語について、低レベルとか、高レベルとか、そういった言葉を使うことがあります。低レベルなプログラミング言語って、一体どんな言語なの? と疑問に思いますね。

パソコンなどの電子機器は、データを保存したり、あるいは何かしらの動作を行う際に、それらの情報全てを数字を使って処理します。つまり、機械にしかわからない『機械語』を使ってデータを処理しているのです。

人間から見ると、機械語は、なんの意味も無いただの数字にしか見えません。ですから、人間でも意味がわかるように、様々な工夫をしたものがプログラミング言語ですね。

実際の機械語で命令できれば一番いいのでしょうが、人間でこれが自在にわかる人はまずいません。そこで、人間でもわかる言葉で文章を書き、それを機械語に翻訳することで、パソコンなどに様々な命令を出すことができるのです。


しかし、プログラミング言語にも様々な種類がありますね。

パソコンなど、電子機器の中で実際に使われる機械語、これに性質が近いものほど低レベルな言語であると言われます。C言語は、比較的低レベルな記述を行うことが可能であり、言い方を変えると、それだけ難しいということでもあります。
最も難解な機械語に近いわけですから、それだけ難しいのです。

我らがVBAはと言うと、これは高レベル、または高級な言語だと言えます。言い換えると、難しいことがよくわからなくても、簡単にプログラムが記述できるということでもあるのです。


要するに、機械語に比較的近い C言語などでは、バイトやビットなどのちょっと難しい知識がどうしても必要になってきます。しかし難しい代わりに、パソコン上のほとんど全ての処理を実現させることができます。
逆にVBAは、バイトやビットなどの知識が無くても、それなりにプログラムが組めます。
しかし、これは言い換えると、できることが限定されているということでもあるのですね。


でも、VBAはできることが少ないんだ……、と落胆する必要はありません。

基本に忠実に、工夫と努力を積み重ねれば、大概のことはできます。ちょっと極端な言い方かもしれませんが、VBAでできないことというのは、本当に高度なことだけです。

例えば、C言語を用いれば、ウィンドウズやマックのような、オペレーションシステムを作ることができてしまいます。当然と言えば当然ですが、VBAにはこんな芸当は無理です。

C言語を用いれば、拡張子が『 DLL 』となっている、いわゆるライブラリファイルを作ることができます。VBAではこれも無理ですね。

でもVBAは、WindowsAPI を使う事だってできますし、DirectX だって使うことができます。ゲームやアプリケーションを作るということに関して言えば、VBAだって結構やるんです! もちろん、それらの高度なテクノロジーを自在に操るには、それなりに高度な知識や、パソコンの基本的なことに関する知識が必要になってきます。

バイトやビットについて理解していることは、こうした高度な処理を行うためには絶対に必要になってきます。一見すると遠回りに感じるかもしれません。しかし、わかっておいて損をすることは無いはずです。ちょっとだけ我慢して、この先の講座を読んでみてください。実はそんなに難しくないんですよ。楽な気持ちで取り組んでみてください。


■たくさんのスイッチ

想像してみてください。

あなたの目の前には、スイッチがあります。
このスイッチは、照明のように、オンオフを切り替えることができる仕組みになっています。

一度スイッチをオンにすると、オフにするまではずっとオンのままです。オフにしたら、スイッチを再び入れるまでは、オフのままです。そんなスイッチです。時間が経ったからといって勝手にオンオフが切り替わったりはしません。


さて、このスイッチ。実はひとつではありません。
スイッチは、8個セットになっています。同じ形の、同じ性能のスイッチが、8個セットになってくっついています。そんなスイッチのセットなんです。

この文章、読んでどんなふうに感じたでしょうか。

実は、これがビットとバイトを簡単に説明している文章です。どういうこと? って感じですよね。説明します。


まず、先ほどの話の中で真っ先に登場した、『スイッチ』。これは一体なんでしょうか。

実は、このスイッチはビットを表しています。

ビットとは、データの最小の単位で、0 か 1 のどちらかを記憶することができます。選択肢が2種類しかないのですね。オンか、オフの2択なわけです。

そして、先ほどの話では、このスイッチが8個くっついてセットになっているという話が出てきましたね。これがバイトです。
バイトとは、オンかオフを切り替えられるスイッチが、8個セットになっているものなのです。

しかし、こんなふうに説明されてもよくわからないと思います。もう少し、踏み込んで考えてみましょう。


■保持できるデータの種類

まずは単純に、スイッチがひとつだけのときを考えてみます。

スイッチがひとつ、つまり 1 ビットで表すことができるのは、オンかオフの2種類だけです。

1 ビット ⇒ 2種類

では、スイッチがふたつ、つまり 2 ビットで表すことができるのは、何種類でしょうか。
これは簡単ですね。1 ビットで2種類のデータを表すことができるわけですから、2 ビットで表すことができるのは、4種類のデータです。

オン × オン
オン × オフ
オフ × オン
オフ × オフ …… 合計 4 種類

このくらいは簡単ですね。

では次に、スイッチが3個の場合はどうでしょうか。

オン × オン × オン
オン × オフ × オン
オフ × オン × オン
オフ × オフ × オン
オン × オン × オフ
オン × オフ × オフ
オフ × オン × オフ
オフ × オフ × オフ …… 合計 8 種類

このようになりますね。

ここまでくると、スイッチの数と、表すことができるデータの種類に、どのような関係があるかわかりますね。

スイッチの数が増えれば増えるほど、表すことができるデータの種類が増えます。そして、スイッチひとつにつき、データの種類が2倍ずつ増えていきます。これを式で表すと次のようになります。

2 ^ スイッチの数

ここで出てきた記号( コレ ⇒ ^ )は、べき算という計算を表す演算子です。べき算というのは、2乗、3乗、などの計算のことですね。
『 2 ^ 2 = 4 』ですし、『 2 ^ 4 = 16 』です。このような計算をべき算というのですね。


さて、それではここで 1 バイトを考えてみましょう。1 バイトは、スイッチが8個くっついたものでしたね。ということは、1 バイトで表すことができるデータの種類は、次のように計算できることになります。

2 ^ 8 = 256

こうなりますね。

つまり、1 バイトで表すことができるデータは、最大で256種類ということになります。

ちょっとややこしくなってきましたね。もう一度整理してみましょう。

1 ビットとは、オンオフを切り替えることができるスイッチのようなもので、0 か 1 を記憶することができる。

1 バイトとは、スイッチが8個セットになっているもの(つまり 8 ビット)で、最大で256種類のデータを記憶することができる。


■変数の型とバイトの関係

ビットとバイトの違いについては理解できましたか?

ビットやバイトの意味がわかると、今まで何気なく行っていたことに、実は重要な意味があったことがわかります。

その最たる例が『変数の型』でしょう。

思い出してみてください。変数は、型によって扱えるデータの種類や大きさが変わりますね。例えば、Integer 型の変数は『 -32768~32767 』の範囲内の数値を扱うことができる変数の型です。

そして、Integer 型の変数は、2 バイトのメモリ領域を使用することになっています。2 バイトって、何種類のデータを表すことができるんでしたっけ?

1 バイト …… 256種類のデータを記憶できる

2 バイト …… 256種類 × 256種類 = 65536種類

このようになります。

『 -32768~32767 』は、マイナスの数値も含まれているわけですから、数の量としては、65536種類の数を扱えることになりますね。

つまり、変数の型と、使用するバイト数には、とても密接な関係があるのです。

他の変数の型でも見てみましょう。

例えば Long 型では、どうなっているのでしょうか。
Long 型の変数は、4 バイトのメモリ領域を使用します。ということは次のようになります。

1 バイト …… 256種類のデータを記憶できる

4 バイト …… 256 × 256 × 256 × 256 …… 4294967296種類

こうなります。

Long 型の変数は、『 -2147483648 ~ 2147483647 』の範囲の数値を扱うことができる変数です。マイナスの領域も含めると、4294967296種類の数値を扱うことができるわけですね。


さらに、VBAには、Byte 型という変数の型があります。これはもう見たまんま、使用する領域も 1 バイトで、扱えるデータも『 0 ~ 255 』までの範囲となっています。0 を含めた256種類のデータを扱うことができるのですね。


このように、変数の型と、使用するバイト数、扱えるデータの量は、それぞれが非常に強い関係性を持っているのですね。実は今回の講座で最も重要なのが、この変数の型とバイトとの関係です。

APIを用いた処理や、DirectXを用いた処理は、基本的にC言語などをベースに作られています。このため、解説書などでは多くの場合、プログラム上で使う変数の型などが、C言語などの変数型で書かれていることが多いです。実はこんなときに、このバイトに関する知識が重要になるケースがあります。


例えば、C言語の『 int 型 』は、4 バイトの領域を使用します。これは、VBAで言うと Long 型と同じメモリの使用量です。ですから、C言語の解説の中で、int 型を使って書かれている部分は、VBAでは Long 型を使って代用できるというわけです。

このほかにも、バイトに関する知識が必要になるケースは、高度なことをやろうとすればそれだけ頻繁に登場します。すぐに何かに役立つというような知識でもないのですが、知っていることは大きな意味を持ちます。

即効性のある知識ではなく、どちらかというと地味な知識ですが、こういった内容をたまにはやるのもいいかなと思いまして、講座にしてみました。VBAでは、こういった知識が無くてもそれなりにできてしまうだけに、どうしてもおざなりになりがちです。
この機会にしっかりと覚えてしまい、基礎の底上げをしておきましょう。

多少難しい内容でしたので、一発で理解できなくてもいいと思います。
焦らずひとつひとつ、習得していきましょう。


■格言

ビットとはデータの最小単位
1ビットは2種類のデータを記憶できる
1バイトは8ビットなので256種類のデータを記憶


かなり長い文章ですね、今回は。大丈夫かな。








Chapter.82 [ ウィンドウメッセージとイベント ]

■ウィンドウ

ウィンドウズを使っていると、いろんな場面でウィンドウが開きます。

フォルダをダブルクリックするとエクスプローラなどが起動し、ウィンドウが開きます。ゲームや、Excel などのアプリケーションを起動したときも、やはりウィンドウが開きますね。

ウィンドウズは、このようにウィンドウを使ってアプリケーションや、様々な機能を提供してくれるオペレーションシステムです。ウィンドウなくして、ウィンドウズは成り立ちません。

今回のテーマは『ウィンドウメッセージとイベント』としました。
VBAには、『イベント』という概念が存在しますが、実はこれがウィンドウメッセージというものと深く関係しています。今回は、ウィンドウメッセージとは何か、そして、ウィンドウメッセージとイベントの関係はどうなっているのか、これについて考えてみることにしましょう。


■ウィンドウメッセージ

皆さんが普段、パソコンを使っているとき、表示されている画面を閉じたいと思ったときはどのようにするでしょうか。
大抵は、ウィンドウの右上にある、『×』ボタンをクリックすると思います。
このとき、ウィンドウズの中ではどんなことが起こっているのでしょう。

実はこのとき、×ボタンが押されたウィンドウには、『ユーザーがウィンドウを閉じようとしているよ!』というメッセージがウィンドウズ本体などから届きます。これがウィンドウメッセージです。これは大抵どんなウィンドウでも同じで、フォルダを表示しているときのウィンドウでも、ゲームをしているときのウィンドウでも、どんなウィンドウでも同様にメッセージが届くことになっています。

ウィンドウメッセージには、上記で挙げた以外にもたくさんのメッセージがあります。
例えば代表的なところでは、次のようなものがあります。

・ディスプレイの解像度が変更された
・ウィンドウが移動、またはサイズ変更された
・キーボードのキーが押された
・マウスが移動している
・マウスのボタンがクリックされた
・スクロールバーが操作された

などなど……そのほかにも膨大な数がある

本当に一部だけですが、とにかく、何らかの操作を行うと、それがウィンドウメッセージとして発行される、ということがわかりますね。

さて、C言語などのプログラミング言語は、これらのメッセージを直接処理することになっていますが、肝心のVBAはどうなのでしょうか。

実は、VBAは、これらのウィンドウメッセージを、我々の見えないところで常に監視しています。そして、必要なものだけ選別して、教えてくれるのです。これが、今回の肝である『 イベント 』です。


■ユーザーフォームとイベント

イベントについては、以前にも何度か解説したことがありましたね。イベントとは、ユーザーの操作のことを表します。ボタンを押したり、マウスを動かしたり、ユーザーフォームを閉じようとしたり、これらの行動がイベントとして通知されてきます。

VBAでは、送られてくるウィンドウメッセージを監視し、イベントとしてプログラムに渡します。C言語などの場合は、膨大なウィンドウメッセージを全て受け取り、必要に応じて処理を選別する必要がありますが、VBAの場合には多少楽になります。なぜなら、VBAが選別してから必要なものだけを通知してくれるからです。

・C言語など
    ウィンドウメッセージを全て受け取る
        ▼
    なんのメッセージが来ているか調べる
        ▼
    必要に応じて処理する

・VBAの場合
    イベントプロシージャを記述しておく
        ▼
    イベントが通知される
        ▼
    プロシージャが実行される

我々VBAプログラマーがやるべきことは、イベントプロシージャを準備しておくことだけです。これだけやっておけば、あとは常にウィンドウメッセージを監視したりする必要はありません。必要なウィンドウメッセージが届いているときには、VBAがイベントという形で教えてくれるからですね。

ちなみに、ここでいうイベントとは、主にユーザーフォーム上のイベントを対象として話をしています。


■様々なイベントの活用

以前、キーボードのキーが押されているかどうかを調べる、APIを使った方法を解説しましたね。

この方法を使うと、今現在、特定のキーが押されているかどうかを調べることができました。講座の中でも、この方法を使ってキーの状態を取得し、シューティングゲームのキャラクターを動かしたりしましたね。

しかし、この方法にはひとつ難点があります。それは『キーが押された瞬間』を調べることができないことです。まぁやりようによっては調べることもできますが、そうなると常にキー入力を監視していなくてはいけなくなります。
シューティングゲームのような、常にループを回し続ける場合はいいのでしょうが、そうでないとしたらキー入力の検知のためだけに、常にループを回しているというのはちょっと無駄な感じがしますね。

この問題を簡単に解決してくれるのが、イベントです。

例えば、ユーザーフォームには、『 KeyDown イベント 』というイベントがあります。キーをダウン、ですから、キーが押された瞬間に発生するイベントです。
このイベントをうまく活用すれば、常にループを回して、キーの状態を調べる必要はありません。なぜなら、キーが押されたその瞬間に、一度だけイベントが発生するからです。

実際に使い方を見てみましょう。

まずは、ユーザーフォームを新規に挿入して、コードを記述します。

Private Sub UserForm_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)

    Dim S As String
    
    S = "キーが押されたよ"
    
    MsgBox S
    
End Sub

プロシージャの引数がちょっと長いので、そのまま見るとプロシージャ名が2行になってしまっているかもしれません。気をつけてくださいね。

さて、このプロシージャは、名前が『 UserForm_KeyDown 』となっていますね。このプロシージャ名から、ユーザーフォームのイベントであることと、キーが押された瞬間のイベントであることがわかります。

UserForm_KeyDown

黄色字で書かれている部分を見ると、これがユーザーフォームのイベントであることがわかります。同様に、緑の文字で書かれている部分を見ると、これがキーダウンのイベントであることがわかりますね。

そして、引数には『 KeyCode 』という項目がありますね。このイベントが呼び出されたときには、既にこの KeyCode の中には何らかのデータが入っています。具体的には整数のデータです。

この KeyCode の値を調べることで、何のキーが押されたのか調べることができます。それでは、何のキーが押されたのか調べることができる形に、先ほどのコードを修正してみましょう。

Private Sub UserForm_KeyDown(ByVal KeyCode As MSForms.ReturnInteger, ByVal Shift As Integer)

    Dim S As String
    Dim Key As String
    
    Key = Chr(KeyCode)
'①
    
    S = Key & "キーが押されたよ"
    
    MsgBox S
    
End Sub

水色の文字で書かれている部分が、あらたに追加された部分です。

このコードを実行すると、何のキーが押されたのか、アルファベットなどで教えてくれます。

470.gif

注目は①の部分ですね。この部分が、押されたキーを表す KeyCode から、押されたキーを表す文字列への変換を行っています。

Key = Chr(KeyCode)

Chr 関数は、ASCII コードと呼ばれる文字セットから、指定された番号の文字列を返してくれる関数です。ASCII コードには、アルファベットや数字、そして一部の記号や、改行文字、タブ文字、半角スペースなどが含まれています。

例えば、アルファベットの大文字の A を表すコードは 65 番です。先ほどのイベントプロシージャで A のキーが押されていたときは、KeyCode に 65 という数字が入っています。それを Chr 関数を使って、A という文字列に変換していたのですね。

このような ASCII コードを使ったプロシージャでは、キーボードの中の、アルファベットや数字が割り当てられているキーを、文字列に変換することができます。Enter キーや、Shift キーなど、割り当てられている文字がないキーもありますが、その場合にも KeyCode の中には特定の値が入るようになっています。

キーダウンイベントを使えば、キーが押された瞬間に、どのキーが押されたのかまで特定することができるのですね。

しかも、ループしながらキーの状態を監視したりする必要はありません。最初に書いたように、VBAがイベントとして通知してくれるのですから、その通知があった時の処理だけを記述しておけばいいのです。何とも簡単ですね。


■イベントを使うメリット・デメリット

さて、今回の例をよく見て考えてみると、イベントを使うことのメリットとデメリットが見えてきます。

イベントの最大の利点は、『VBAが必要に応じて自動的に発行してくれる』ということでしょう。キーの入力が全く行われていないときに、キーの入力状態を調べるのは無意味です。しかし、イベントを使えば、キー押された瞬間に、タイミングよく処理を実行することができるわけですね。

しかし、イベントを利用した方法では、シューティングゲームなどの激しい入力を必要とするゲームは作成しにくくなります。キーが押された瞬間しかわからないので、常に押されているかどうかを調べることができないからですね。

イベントには様々な種類があり、キーボードだけでなく、マウスの動きやクリックの状態を調べることもできます。しかし、どのイベントにも、向き不向きがあるのです。
イベントの特性をよく理解し、もっとも適した処理を選択するようにしましょう。

今回はキーの入力に関することが主になってしまいましたが、将来的には、マウスの状態を調べたり、その他のイベントの使い方についても取り上げるかもしれません。
まずは、イベントがどのように発生し、どのような特徴を持っているのか、それをよく理解しましょう。焦りは禁物、基本的なことこそしっかりと習得しておきましょう。



■格言

ウィンドウメッセージを使って
ウィンドウズは処理されている
VBAではイベントという概念を用いて
ウィンドウメッセージを処理している


イベントはとても便利です。特性をよく理解しておきましょう。








メールフォーム

影斬に物申すという方はこちら

名前 :
メール:
件名 :
本文 :

可能な限り要望には応えますが、必ず返信や回答ができることを、保障するものではありません。
ご了承ください。

Chapters

コンテンツ一覧


■Chapter 一覧■
    全てのChapterの一覧です。
    直接アクセスしたい方はこちらをご利用下さい。

    Chapter.1 [ 知っておくべき心得 ]
    Chapter.2 [ Excelってなんだろう ]
    Chapter.3 [ Excelの基本画面 ]
    Chapter.4 [ VBAとは? ]
    Chapter.5 [ モジュールについて ]
    Chapter.6 [ 変数 ]
    Chapter.7 [ 変数の型と宣言 ]
    Chapter.8 [ プロシージャとスコープ ]
    Chapter.9 [ ゲームつくる様々な手法 ]
    Chapter.10 [ ユーザーフォーム ]
    Chapter.11 [ プロパティウィンドウ ]
    Chapter.12 [ 乱数 ]
    Chapter.13 [ 条件分岐 ]
    Chapter.14 [ ゲーム画面のデザイン ]
    Chapter.15 [ コード記述の基本作法 ]
    Chapter.16 [ じゃんけんゲーム:1 名前をつける ]
    Chapter.17 [ じゃんけんゲーム:2 フォームの起動 ]
    Chapter.18 [ じゃんけんゲーム:3 乱数の種 ]
    Chapter.19 [ じゃんけんゲーム:4 イベント ]
    Chapter.20 [ じゃんけんゲーム:5 引数 ]
    Chapter.21 [ じゃんけんゲーム:6 役判定 ]
    Chapter.22 [ じゃんけんゲーム:7 予測と制限 ]
    Chapter.23 [ Withステートメント ]
    Chapter.24 [ 画像を表示させる ]
    Chapter.25 [ 画像表示の発展形 ]
    Chapter.26 [ 繰り返し処理 For文 ]
    Chapter.27 [ 繰り返し処理 Do~Loop文 ]
    Chapter.28 [ Exitステートメント ]
    Chapter.29 [ フォーム上の位置情報 ]
    Chapter.30 [ API基礎知識 ]
    Chapter.31 [ API補足知識 ]
    Chapter.32 [ メインループを考える ]
    Chapter.33 [ 同期処理の概念 ]
    Chapter.34 [ 移動処理その1:画面設定と考え方 ]
    Chapter.35 [ 移動処理その2:DoEvents ]
    Chapter.36 [ 移動処理その3:キー入力判定API ]
    Chapter.37 [ 条件分岐のさらなる探求 Select Case ]
    Chapter.38 [ アニメーション ]
    Chapter.39 [ 配列変数 ]
    Chapter.40 [ ゲームの初期化 ]
    Chapter.41 [ シューティングゲーム1:ゲーム設計 ]
    Chapter.42 [ シューティングゲーム2:メインプロセス ]
    Chapter.43 [ シューティングゲーム3:構造体 ]
    Chapter.44 [ シューティングゲーム4:定数 ]
    Chapter.45 [ シューティングゲーム5:プレイヤーキャラクター ]
    Chapter.46 [ シューティングゲーム6:ショットを撃つ① ]
    Chapter.47 [ シューティングゲーム7:ショットを撃つ② ]
    Chapter.48 [ シューティングゲーム8:Mod演算子の活用 ]
    Chapter.49 [ シューティングゲーム9:敵キャラクター登場 ]
    Chapter.50 [ シューティングゲーム10:衝突判定 ]
    Chapter.51 [ シューティングゲーム11:衝突の実体 ]
    Chapter.52 [ シューティングゲーム12:敵の攻撃 ]
    Chapter.53 [ シューティングゲーム13:爆発エフェクト ]
    Chapter.54 [ シューティングゲーム14:残機数表示① ]
    Chapter.55 [ シューティングゲーム15:残機数表示② ]
    Chapter.56 [ シューティングゲーム16:スコアの表示 ]
    Chapter.57 [ シューティングゲーム17:タイトル画面 ]
    Chapter.58 [ シューティングゲーム18:ボスキャラクター ]
    Chapter.59 [ シューティングゲーム19:最後の仕上げへ ]
    Chapter.60 [ シューティングゲーム20:いよいよ完成STG ]
    Chapter.61 [ カードゲームで使えるめくり効果 ]
    Chapter.62 [ ラジアンと角度 ]
    Chapter.63 [ ラジアンの活用:円運動 ]
    Chapter.64 [ ラジアンの活用:任意の角度へ移動する ]
    Chapter.65 [ APIによるサウンド再生:基礎 ]
    Chapter.66 [ APIによるサウンド再生:MIDIと多重再生 ]
    Chapter.67 [ APIによるサウンド再生:MCIコマンドとループ再生 ]
    Chapter.68 [ Function プロシージャ ]
    Chapter.69 [ 値渡しと参照渡し ]
    Chapter.70 [ デバッグ1:イミディエイトウィンドウ ]
    Chapter.71 [ デバッグ2:ローカルウィンドウ ]
    Chapter.72 [ デバッグ3:コード実行の中断 ]
    Chapter.73 [ オブジェクトってなんだ ]
    Chapter.74 [ プロパティ・メソッド・イベント ]
    Chapter.75 [ オブジェクト変数 ]
    Chapter.76 [ オブジェクトとコレクション ]
    Chapter.77 [ 特殊な繰り返し:For Each ]
    Chapter.78 [ エラー処理 ]
    Chapter.79 [ On Error と GoTo文 ]
    Chapter.80 [ Resumeステートメント ]
    Chapter.81 [ バイトとビット ]
    Chapter.82 [ ウィンドウメッセージとイベント ]
    Chapter.83 [ 文字列の基礎 ]
    Chapter.84 [ 文字列操作① ]
    Chapter.85 [ 文字列操作② ]
    Chapter.86 [ タイピングゲーム1:仕様を決める ]
    Chapter.87 [ タイピングゲーム2:キー入力検知 ]
    Chapter.88 [ タイピングゲーム3:文字列照合 ]
    Chapter.89 [ タイピングゲーム4:判定関数 ]
    Chapter.90 [ タイピングゲーム5:ゲーム画面設計 ]
    Chapter.91 [ タイピングゲーム6:問題文のソート ]
    Chapter.92 [ タイピングゲーム7:動的配列 ]
    Chapter.93 [ タイピングゲーム8:キーダウンイベント ]
    Chapter.94 [ タイピングゲーム9:正打数の表示 ]
    Chapter.95 [ タイピングゲーム10:タイムの表示 ]
    Chapter.96 [ クリックゲーム1:イベントの種類 ]
    Chapter.97 [ クリックゲーム2:画面設計 ]
    Chapter.98 [ クリックゲーム3:クリック座標検知 ]
    Chapter.99 [ クリックゲーム4:キャラクター準備 ]
    Chapter.100 [ クリックゲーム5:キャラクターの配置 ]
    Chapter.101 [ クリックゲーム6:キャラクター移動とNot演算子 ]
    Chapter.102 [ クリックゲーム7:クリックのヒット判定 ]
    Chapter.103 [ クリックゲーム8:ヒットマークエフェクト ]
    Chapter.104 [ クリックゲーム9:サウンド処理の実装 ]
    Chapter.105 [ クリックゲーム10:マウスカーソルの変更 ]
    Chapter.106 [ ブロック崩しゲーム1:仕様と概要を決める ]
    Chapter.107 [ ブロック崩しゲーム2:基本概念の確認 ]
    Chapter.108 [ ブロック崩しゲーム3:ベクトルとは ]
    Chapter.109 [ ブロック崩しゲーム4:変数や定数の宣言 ]
    Chapter.110 [ ブロック崩しゲーム5:初期化処理の実装 ]
    Chapter.111 [ ブロック崩しゲーム6:ブロックの配置 ]
    Chapter.112 [ ブロック崩しゲーム7:根幹処理とバーの処理 ]
    Chapter.113 [ ブロック崩しゲーム8:線分と線分の交差を判定 ]
    Chapter.114 [ ブロック崩しゲーム9:線分同士の交点 ]
    Chapter.115 [ ブロック崩しゲーム10:ボールの処理 ]
    Chapter.116 [ ブロック崩しゲーム11:最終調整して完成へ ]
    Chapter.117 [ テキストファイル操作基礎 ]
    Chapter.118 [ テキストファイル操作:読み込み編 ]
    Chapter.119 [ テキストファイル操作:CSV読み込み編 ]
    Chapter.120 [ テキストファイル操作:様々な読込編 ]
    Chapter.121 [ テキストファイル操作:バイナリ編 ]
    Chapter.122 [ テキストファイル操作:暗号化編 ]
    Chapter.123 [ テキストファイル操作:復号化編 ]
    Chapter.124 [ クラスモジュールとは ]
    Chapter.125 [ クラスモジュール:メソッド編 ]
    Chapter.126 [ クラスモジュール:プロパティ編 ]
    Chapter.127 [ クラスモジュール:イベント拡張編 ]
    Chapter.128 [ クラスモジュール:イベント自作編 ]
    Chapter.129 [ APIによる描画処理1:ハンドル ]
    Chapter.130 [ APIによる描画処理2:デバイスコンテキスト ]
    Chapter.131 [ APIによる描画処理3:ペン オブジェクト ]
    Chapter.132 [ APIによる描画処理4:ブラシ オブジェクト ]
    Chapter.133 [ APIによる描画処理5:図形描画準備編 ]
    Chapter.134 [ APIによる描画処理6:図形描画実践編 ]
    Chapter.135 [ APIによる描画処理7:画像描画の仕組み編 ]
    Chapter.136 [ APIによる描画処理8:ビットブロック転送編 ]
    Chapter.137 [ APIによる描画処理9:ラスタオペレーション ]
    Chapter.138 [ APIによる描画処理10:マスク描画 概念編 ]
    Chapter.139 [ APIによる描画処理11:マスク描画 実践編 ]


    コードやVBAに関する質問などはサポート掲示板(別館)までお気軽にどうぞ。




fc2 seotool Excel VBA ゲーム プログラミング 講座

Counter

twitter


Shadow BBS - 影掲示板

VBA 関連書籍



上記広告は1ヶ月以上更新のないブログに表示されています。新しい記事を書くことで広告を消せます。