法政大学国際文化学部

情報コミュニケーションI

担当 重定 如彦

20031211

 

·        配列変数(続き)

オブジェクト

プロパティ

設定値

グループボックス

(name)

外側のグループボックスの名前を「成績のグループ」に設定。

それ以外の3つのグループボックスの名前は変更しなくても良い。

テキストボックス

Text

1,2,3,4,5のラベルの下のテキストボックスに0〜100までの

好きな整数を入力する。図8−13と同じである必要はありません。

ボタン

Text

計算

図8−14

 

 プログラムを記述する前に、それぞれのコントロールがどう表現されるかを説明します。

最後に作成した「成績のグループ」というグループボックスには、3つのグループボックスが配置されています。従って、3つのグループボックスは以下のように表現することができます。

 

国語の点数の右のグループボックス

成績のグループ.Controls(0)

算数の点数の右のグループボックス

成績のグループ.Controls(1)

理科の点数の右のグループボックス

成績のグループ.Controls(2)

 

 国語の点数の右のグループボックスの中の7つのテキストボックスは以下のように表現することができます。

 

生徒番号1の下のテキストボックス

成績のグループ.Controls(0).Controls(0)

生徒番号2の下のテキストボックス

成績のグループ.Controls(0).Controls(1)

・・・

 

生徒番号5の下のテキストボックス

成績のグループ.Controls(0).Controls(4)

合計点の下のテキストボックス

成績のグループ.Controls(0).Controls(5)

平均点の下のテキストボックス

成績のグループ.Controls(0).Controls(6)

 

 Controlsが2つ続いている為に、意味が良くわからないと思われる方が多いと思いますが、落ち着いて考えればそれほど難くはありません。下の図のように、「成績のグループ.Controls(0)」が国語の点数の右のグループボックスのことを表しているということが理解できれば、この後に .Controls(0) と記述すれば、国語の点数の右のグループボックスの中に最初に配置したコントロールを表すということが理解できるのではないでしょうか。

国語の点数の右の

グループボックスを表す

 
 


成績のグループ.Controls(0).Controls(0)

 

 

 理科と社会のテキストボックスも全く同様の方法で表すことができます。それぞれどのように表されるか、各自考えてみてください。

2. イベントハンドラを作成する

 それぞれのテキストボックスをどう表現すれば良いかがわかりましたので、次はイベントハンドラを記述してみましょう。計算ボタンをダブルクリックし、イベントハンドラを作成し、以下のようなプログラムを入力して下さい。

このプログラムは以下の4つの部分から構成されています。それぞれ順を追って説明します。

     定数の宣言

     変数の宣言

     テキストボックスの内容を2次元配列変数「成績」に代入する。

     変数「成績」を使って、それぞれの科目の合計点を計算し、テキストボックスに表示する。

定数の宣言:

 Const で始まる以下のプログラムは定数を宣言しています。

 

定数は以下のように宣言します。

Const 定数名 As 型 = 値

定数は変数と非常に良く似ていますが以下の点で異なります。

     宣言時に「Dim」ではなく「Const」と記述する。

     宣言時に最後に「= 値」を記述し、宣言時に定数の値を設定する必要がある。

     定数は変数と異なり、宣言時に設定した値で固定される。従って、代入文を使って定数に別の値を代入することはできない。

 定数を使う利点には以下のようなものがあります。

     意味のある数字に名前をつけることで、プログラムを読みやすくすることができる。
例えば、このプログラムでは、For文で、生徒数の数だけ繰り返し計算を行います。この時、
   For i = 1 To 5
と記述した場合と、生徒数という定数を宣言し、
  For I = 1 To 生徒数
と記述した場合を比べてみてください。後者のほうがはるかにプログラムの意味がわかりやすいはずです。定数を使って、プログラムの意味をわかりやすくすることで、プログラムのエラーを見つけやすくなるという利点がありますので、積極的に使うことをお勧めします。

     プログラムで、数字を変更する場合に変更を簡単に行うことができる。
例えば、この例題では生徒数が5人の場合の計算を行いました。もし、このプログラムで計算する生徒の数を5人から4人に変更した場合、生徒数を定数で宣言し、それを使ってプログラムを記述しているので、定数の宣言の部分を
       Const 生徒数 As Integer = 4         '生徒の数(4人)を表す定数

と変更するだけでOKです。

もし、定数を使わなかった場合は、この例題のプログラムの中の「生徒数」と記述されている部分はすべて5と記述する必要があります。この場合、計算する生徒数を4人に変更するには、該当する5をすべて4に変更する必要があります。これはプログラムの数字の一つ一つの意味を考えながら行わなければならないため、かなり大変な作業ですし、一つでも数字を変更し忘れるとプログラムは正しく変更されなくなります。

 

変数の宣言:
 Dim文で記述された2行で、成績を格納する2次元配列変数「成績」と、カウンタ変数「i」,「j」、合計点を計算数変数「合計」を宣言しています。2次元配列変数「成績」のそれぞれの要素は以下のような意味をことにします。

     1つ目の要素:科目を表す
数字の意味は1:国語、2:理科、3:社会とします。

     2つ目の要素:生徒番号を表す

テキストボックスの内容を2次元配列変数「成績」に代入する:

 2次元配列変数「成績」にテキストボックスの内容を繰り返しを使って代入します。2次元配列変数を繰り返しを使って扱う場合、上記のプログラムのように、繰り返しを2つ入れ子にして記述することで、全ての要素に対して計算を行うことができるようになります。外側の繰り返しで、「それぞれの科目」について繰り返しを行い、内側の繰り返しで「それぞれの科目」に対する、「それぞれの生徒」について繰り返しを行います。

 プログラミングに慣れないうちはこのような繰り返しの入れ子は理解しにくい方が多いのではないかと思います。うまく理解できない方は、フローチャートを書くなどして、プログラムの流れを追って何故このプログラムで正しく代入できるかどうかを確認してください。

 

変数「成績」を使って、それぞれの科目の合計点を計算し、答えをテキストボックスに表示する:

 

 こちらも同様に、繰り返しを入れ子にすることで、それぞれの科目の合計を計算しています。計算結果をテキストボックスに代入する部分は、外側の繰り返しのブロックに記述する必要がある点に注意して下さい。こちらについても同様に、うまく理解できない方は、プログラムの流れを追ってください。

3.プログラムの実行と確認

プログラムを実行し、正しく動作することを確認して下さい(図8−15)。

図8−15

 

補足:ツールボックスから直接グループボックス内にテキストボックスを作成するという方法で、グループボックスにテキストボックスを配置した場合、最後に配置したテキストボックスが 0 番目のコレクションになってしまうようです。もしその方法で配置してしまうと、上記のプログラムは正しく動かなくなりますので、その場合は一旦グループボックス内のテキストボックスをグループボックスの外に動かしてから、順番にグループボックス内に配置しなおすという作業を行って下さい。

 

Tips 3次元以上の配列変数

Visual Basic .Netでは3次元以上の配列変数を使うこともできます。3次元配列変数を定義するには、以下のように、要素数を,で3つ区切ります。

 

Dim 変数名(1つ目の要素数,2つ目の要素数,3つ目の要素数) As 型名

 

同様の方法で、4次元以上の配列変数も宣言することができます。

 

·       プロシージャ

 プログラミングでは、プロシージャという方法を使うことで、記述したプログラムを何度も再利用することができます。プロシージャもVisual Basic .Netの制御構造の一つです。プロシージャは、実はこれまでに何度も使って登場しています。以下はすべてプロシージャです。

     オブジェクトのメソッド

     様々な関数

     イベントハンドラ

 プロシージャには以下の特徴があります。

     プロシージャにはそれぞれ名前がある。

     プロシージャは プロシージャ名(引数,・・・) と記述することで、プログラムの好きな場所で何度でも利用することが可能である。これを「プロシージャ呼び出し」と呼びます。

     プロシージャを実行すると、その時点でプログラムの実行がプロシージャの処理へ移り、プロシージャの処理が終了すると、プロシージャが記述された部分に実行が戻る。

     プロシージャには引数を使うことで、値を受け渡すことができる。

     プロシージャは、プロシージャの終了後に結果を返すことができる。これを「返り値」と呼びます。

 

例えば以下のプログラムは、平方根()を計算しするMath.Sqrt(100)というプロシージャを使ったプログラムです。

A = Math.Sqrt(100)

このプログラムを実行すると、以下のような処理が行われます。

プロシージャには以下のような利点があります。

     一度プロシージャを作成しさえすれば、何度でも利用することが可能。

     プロシージャの動作(Math.Sqrtプロシージャの場合、引数の平方根を計算するということ)さえ知っていれば、具体的にプロシージャの内容を知らなくても、誰でも利用することができる。

Tips プロシージャとライブラリ

プロシージャの利点は、自動車の運転の仕方を知っていれば自動車がどのような原理で動くかを知らなくても自動車を運転できるという事に似ています。このように、よく使う計算をプロシージャとして用意し、誰でも利用することができるようにしたものを「ライブラリ」と呼ぶことがあります。関数のところで紹介した様々な関数はすべてライブラリです。
9.1 Sub プロシージャ

 プロシージャは、これまでの例のように、あらかじめ用意されたものを利用するだけでなく自分で作成することも可能です。プロシージャには、プロシージャの内容を実行した結果、値を返すプロシージャ値を返さないプロシージャの2種類に分類することができます。

 ここでは、まず値を返さないSub プロシージャの作成方法について解説します。

Subプロシージャは以下の形式で記述します。

 

 Public Sub プロシージャ名(ByVal引数名1 As 引数名1の型,・・・)

  プロシージャのブロック

 End Sub

 

プロシージャの記述について一つ一つ解説します。

     Public
 この部分には実は「Public」以外の記述を行う場合がありますが、本書の範囲を超えてしまうので、ここでは解説しません。本書の範囲では、プロシージャを作成する際には最初に「Public」を記述すると覚えておけばよいでしょう。

     Sub
 「Sub」はこれから記述するプロシージャが値を返さないプロシージャであることを表します。

     プロシージャ名
 プロシージャ名には任意の名前を付けることが可能です。プロシージャ名は、できるだけプロシージャが何を行うものであるかを表す名前を付けることをお勧めします。Visual Basic .Netでは日本語のプロシージャ名を付けることができるので、プロシージャ名は日本語で作成すると良いでしょう。

     引数
 プロシージャに値を渡す必要がある場合、渡された値を格納する為の変数(引数)を()の中に記述します。引数の宣言は先頭にDimではなくByValと記述する点を除けば変数の宣言時と同じ方法で行います。引数が複数ある場合は、「,」で区切って記述します。また、引数が存在しない場合でも括弧を省略することはできずその場合は()と記述する必要がある点に注意して下さい。

 

     プロシージャのブロック
 プロシージャで実行するプログラムを記述します。これまで説明した、条件分岐、繰り返しなどはすべて記述することができます。

     End Sub
プロシージャの終わりを表します。End Subを実行すると、プロシージャを呼び出した場所に、プログラムの実行が戻ります。

例題9−1 Subプロシージャを使ったプログラム

 例題6−2をSubプロシージャを使ったプログラムに書き換えてみます。例題6−1のプログラムを開き、イベントプロシージャを以下のように書き換えてください。

 

 このプログラムでは、「合格判定」という名前の合否を判定し、結果を表示するプロシージャを記述し、それを呼び出しています。
 1.プロシージャの説明

プロシージャ「合格判定」では、「得点」という点数を格納する引数と、「成績のテキストボックス」という結果を表示するテキストボックスを格納する引数を宣言し、プロシージャの中ではそれらの引数を使って計算を行っています。なお、テキストボックスなどのコントロールを引数とする場合は、引数の型に System.Object と記述してください。

2.プロシージャ呼び出し部分の説明

  プロシージャ呼び出しは、 

合格判定(Val(点数.Text), 評価)

の行で行われています。()のにはプロシージャに渡す2つの引数が記述されており、それぞれが、プロシージャの引数に代入されます。上記の場合、「Val(点数.Text)の計算結果」が引数「得点」に、「評価という名前のテキストボックス」が引数「成績のテキストボックス」に代入されます。従って、呼び出されたプロシージャ内で行われる計算は例題6−2のものと全く同じになります。各自、例題6−2のプログラムと上記のプログラムを見比べて、どこがどう対応しているかを確認して下さい。

この例ではあまりプロシージャの恩恵を実感できないかもしれませんが、もし同じ条件で複数の成績を判定したい場合は、上記のように合格判定というプロシージャを用意しておけば、

 

合格判定(Val(算数の点数.Text, 算数の評価)

合格判定(Val(理科の点数.Text, 理科の評価)

 

のようにプロシージャ呼び出しを利用することで簡単に判定を行う事が可能になります。

 

Tips イベントハンドラとプロシージャ

 イベントハンドラはSubプロシージャの一種です。例えばボタンコントロールをダブルクリックすると以下のようなイベントハンドラが作成されますが、これはさきほど説明したSubプロシージャの記述方法とほとんど同じ方法で記述されています。

 

   Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click

    End Sub

 

 先ほど説明したSubプロシージャの記述と異なる部分について簡単に説明します。

Privateは本書の範囲を超えていますので、ここでは意味は説明しません。ここでは、Publicの代わりに記述されていると思ってください。ByValについては後述します。最後に記述されている Handles Button1.Click は、Button1という名前のオブジェクトがクリック Clickされた時にこのSub プロシージャを実行するという意味を持ちます。

 

9.2 Function プロシージャ

 Functionプロシージャでは、プロシージャの終了後に、プロシージャで行ったプログラムの実行結果を返す事ができます。Functionプロシージャは以下の形式で記述します。

 

 Public Function プロシージャ名(引数名1 As 引数名1の型,・・・)As 返り値の型

  プロシージャのブロック

  Return

 End Function

 Functionプロシージャの記述方法は、Subプロシージャとほぼ同じですが、以下の点が異なっています。

     1行目のPublicや最終行のEndの後に、SubではなくFunctionと記述する。

     一行目の引数の()の後に返り値の型を記述する必要がある。
Function
プロシージャでは、プロシージャの実行後に値を返すので、その値の型をここに記述する必要があります。

 

     Return文によって値を返す。
プロシージャが返す値は、Return文によって指定します。
  Return
と記述された文が実行されると、プロシージャの実行はそこで終了し、「式」が計算され、その結果が返り値として返されます。Functionプロシージャを式の中で呼び出した場合、Functionプロシージャの部分は「返り値」に置き換えられて計算が行われます。式の中で呼ばれかなかった場合は、返り値の値は無視されます。

例題9−2 Functionプロシージャを使ったプログラム例

 例題5−4をFunctionプロシージャを使ってプログラムを作成します。例題5-4を開き、以下のようにプログラムを変更して下さい。


 

 1.プロシージャの説明

この例題では、桁あわせを行う部分をプロシージャ「桁あわせ」で行っています。プロシージャ桁あわせでは、「数値」という名前の引数に桁合わせを行う数字を代入し、それを使って、Format関数で数値を小数点以下3桁までの文字列に変換しています。結果は文字列なので、プロシージャの型をStringに指定する必要がある点に注意して下さい。

2.プロシージャ呼び出し部分の説明

  プロシージャ呼び出し側では、引数に数値の部分を記述して呼び出しを行っています。 プロシージャを使った利点の一つに、プログラムの変更が容易になるというものがあります。例えば、上記のプログラムを小数点以下第4桁まで表示するように変更するには、プロシージャ「桁あわせ」の中身を Return Format(数値, #.0000“)に変更するだけで済みますが、例題5−4のように記述した場合は、3つのFormat関数の中の#.000をそれぞれ#.0000に変更する必要があります。例題5−4の場合は3つしかないので変更はまだ楽なほうですが、もし変更が必要な箇所がプログラムの中のあちこちに散らばっていた場合はミスなく変更するだけでも大変な作業が必要となります。

 

 

 

 

9.3 変数のスコープ

9.3.1 局所変数と大域変数

 Visual Basic .Netでは、プロシージャの引数や、プロシージャ内で宣言された変数は、プロシージャのブロックの中でしか使用することはできません。また、プロシージャに限らず、If文や、For文などの制御構造のブロックの中で変数を定義した場合は、その変数はそのブロックの中でしか使用できないというきまりがあります。このような変数を利用できる有効範囲のことを変数のスコープ(Scope)と呼びます。 

 この説明ではわかりにくいと思いますので、図で説明します。

 例えば下のプログラムでは、プロシージャ1で変数xが引数として宣言され、変数aがプロシージャ内で宣言されています。この場合、x とaはそれらの変数が宣言されたプロシージャ1のブロックの中でしか利用することはできません。つまり、プロシージャ2のブロック内で a = 5 のような、代入文を記述すると、プロシージャ2で変数aが宣言されていないため、エラーになってしまいます。

 

    Public Sub プロシージャ1(ByVal x As Integer)

変数aと変数xの有効範囲

 
        Dim a As Integer

        プロシージャ1のブロック

    End Sub

 

    Public Sub プロシージャ2()

        プロシージャ2のブロック

    End Sub

 

次の例では、変数A,B,Cがそれぞれ別々のブロックの中で定義されています。この場合、それぞれの変数の有効範囲は以下のようになります。

 

    Public Sub プロシージャ()

        Dim A As Integer

        For A = 1 To 10

Aの有効範囲

 
            Dim B As Integer

Bの有効範囲

 
            プログラム・・・

            If B > 10 Then

Cの有効範囲

 
                Dim C As Integer

                プログラム・・・

            End If

        Next A

    End Sub

 

 このように変数の有効範囲が決まっている変数のことを「局所変数」と呼びます。局所変数は、変数のスコープ(有効範囲)が終了した時点で、自動的に破棄されてしまうため、変数のスコープの外では使用することができない点に注意が必要です。

 変数の有効範囲がどこまでかを知る最も簡単な方法は、インデントを見ることです。

上記の図のように、変数が定義された行と比較してインデントが同じか、それより右にずれている部分がその変数の有効範囲に一致します。

 一方「局所変数」に対して、一度定義すればどんな場所でも使用することができる変数のことを「大域変数」と呼びます。大域変数は、プロシージャの外に記述することで定義することができます。

 例えば以下のように記述を行うと、変数Aをどのプロシージャ内でも使用することが可能です。

 

    Dim A As Integer

    Public Sub プロシージャ名()

        プログラムのブロック

    End Sub

 

9.3.2 同じ名前の変数名

 Visual Basic .Netでは同じブロック内では、同じ名前の変数を複数宣言することはできませんが、ブロックが異なっていれば例え外側のブロックで同じ名前の変数が宣言されていたとしても、同じ変数を複数宣言することが可能です。例えば、以下のプログラムは変数Aを同じブロックで2回宣言しているのでエラーになります。

 

    Public Sub プロシージャ名()

        Dim A As Integer

        Dim A As Integer

        プログラム

    End Sub

 

 次のプログラムは変数Aを2回宣言していますが、それぞれ別のブロックで宣言しているのでエラーにはなりません。

 

 Public Sub プロシージャ名()       外側のブロックのA 内側のブロックのA

   Dim A As Integer                                          未定義

    A = 0                                                     未定義

    IF A == 0 Then                                            未定義

      Dim A As Integer                                       

      A = 10                                                  10

    End If                                                    未定義

  A = A + 1                                                 未定義

    End Sub

 

 上記の例のように、外側のブロックですでに宣言されている変数を別の内側のブロックで宣言した場合は、それぞれの変数は名前は同じですが、別々のものとして扱われ、実際の計算では内側のブロックで定義された変数が有効となります。

 上記の例でプログラムの実行と共に変数Aの値がどうかわるかを右に示します。変数の値で網掛けになっている部分がプログラム上で、Aの値として利用される部分です。

 上記の例では、多くの方が、変数名の重複はややこしいだけで利点がないと思われるでしょう。そこで、いくつか変数名の重複が必要になる具体的な例を挙げることにします。

例その1

変数名の重複が最も良く使われるのは、プロシージャ内での変数の宣言です。例えば、テキストボックスに入力した数字長さを半径とする、「円周の長さ」、「円の面積」を求め、答えをテキストボックスに表示するプログラムを、Functionプロシージャを作成した場合を考えて見ましょう。

円周の長さを求めるプロシージャは以下のようになります。

 

    Public Function 円周の長さ(ByVal 半径 As Double) As Double

        Return 2 * Math.PI * 半径

    End Function

 

同様に、円の面積を求めるプロシージャは以下のようになります。

 

    Public Function 円の面積(ByVal 半径 As Double) As Double

        Return Math.PI * 半径 * 半径

    End Function

 

 勘の良い方は、この時点で、「半径」という同じ名前の変数を、2つのプロシージャで2度宣言していることに気づかれたのではないかと思います。この例のように、同じ意味のデータを使って計算を行うプロシージャを複数記述する場合、同じ名前の変数を使いたいということが非常に頻繁におこります。もし、変数名の重複定義が許されなければ、上記のプログラムはエラーとなってしまうので、プロシージャ毎に、同じ「半径」というデータを扱うにもかかわらず引数の名前を別のものにする必要があります。上記のような記述ができるのは、「ブロックが異なれば同じ名前の変数を定義することができる」という決まりがあるからなのです。

 

 例その2

 次の例では、1から10までの数字それぞれに対して、1からその数字までの合計を計算し、結果を「合計」という配列変数に格納する「数字の計算」というプロシージャを作成します。このプログラムでは、数字の合計を計算するために、「数字のの合計」という名前のプロシージャを作成し、それを使って計算を行うことにします。

 

    Public Function 数字の計算(ByVal n As Integer)

        Dim 合計(10) As Integer

        Dim i As Integer

        For i = 1 To 10

            合計(i) = 数字の合計(i)

        Next i

    End Function

 

    Public Function 数字の合計(ByVal n As Integer) As Integer

        Dim i, 合計 As Integer

        合計 = 0

        For i = i To n

            合計 = 合計 + i

        Next

        Return 合計

    End Function

 

 

ここでそれぞれのプロシージャで、共に変数「i」と変数「合計」を定義している点に注目して下さい。このプログラムが正しく動作するのは、プロシージャ「数字の計算」内の変数「i」と変数「合計」がプロシージャ「数字の合計」の変数「i」と変数「合計」とは名前は同じであるが別の変数として計算されているからです。

 実際に流れを追って手順を見てみましょう。プログラムを実行し、プロシージャ「数字の計算」内の繰り返しで、「i」が5になった時のプログラムの動作の流れを以下に記述します。

 

 

 

 

 

        i=5の時に「数字の計算」内の以下の行が実行された場合の処理の流れ

                                        数字の計算内の変数i 数字の合計内の変数i

            合計(i) = 数字の合計(i)                           未定義

 

    Public Function 数字の合計(ByVal n As Integer) As Integer

        Dim i, 合計 As Integer                               

        合計 = 0                                                     

        For i = i To n                                        1〜5まで変化

            合計 = 合計 + i                                   1〜5まで変化

        Next                                                  1〜5まで変化

        Return 合計                                          

    End Function

 

プログラムの右に記述されている数字がそれぞれのブロックの変数iの値です。網掛けになっている数字が実際にプログラムで使用される変数です。上記のように、「数字の計算の変数i」は、プロシージャ「数字の合計」内では一切使われず、プロシージャ「数字の合計」内でいくら「変数の合計の変数i」を変化させても「数字の合計の変数i」が変化することはありません。

この例で2つのプロシージャで同じ名前の変数を使っても何故うまくプログラムが動作するかについて、各自プログラムの流れを追って理解してください。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

質問のメールなどは、sigesada@edu.i.hosei.ac.jpまでお願いします。

授業の資料の最新版はhttp://www.edu.i.hosei.ac.jp/~sigesada/にあります。