さて今日はVisual Basicでプログラミングの日。
ずいぶん機能が複雑だったこともあって1日では済まなかった。
まぁ1日で済んでしまっても困るのだが。
Visual Basicというと触れたことがあるかないかで言うとあるという答えになるが、
このVisual BasicというのはVisual Basic .NETのことで、かなりC#の要素を取り入れている。
なのでC#を触れている人からすればわりに易しい。まぁBasic自体そうも難しいもんではないしね。
逆にVB.NETを触れたことがある人ならC#はわりに易しいかもしれない。
ただ今回の開発環境はVisual Basic 6.0、ともかくなかなか信じがたいプログラミング言語だった。
とりあえずボタンに動作を割り付けてみることにした。デザインでボタンをクリックしてイベントハンドラに動作を書き込む。
Private Sub Foo_Click()
If NumBox = "0" Then
NumBox = CStr(1)
ElseIf NumBox = "-0" Then
NumBox = CStr(-1)
Else
NumBox = NumBox + CStr(1)
End If
End Sub
まぁ動作の意味はともかく、条件分岐である。
Basicでは If (条件式) Then (真のときの処理) Else (偽のときの処理) という書き方をする。
ただ、実際には処理が1行で済むことも少ないので、処理に代えて行数とかラベルとかを書くこともしばしば。
けどVisual Basicではブロックで書くことが普通なのでその点ではCやらとそう差があるわけではない。
If (条件式) Then まで1行で書いて、次の行から真の時の処理のブロックが始まる。
ElseIf (条件式) Then とか Else とか書いたらブロックが終わって、新しいブロックが始まる。
そして忘れてはいけないのが最後のEnd If、これが抜けるとうまくいかない。EndではなくてEnd Ifなので注意。
あと、NumBoxはテキストボックスですが、C#だと NumBox.Text=1.ToString(); とか書くところを、 NumBox=CStr(1) と書いている。
CStrは文字列への変換関数のようなものらしい。NumBoxに直接文字列を代入すれば表示される文字列に入るようで。
NumBox.Caption=CStr(1) と書いてもいいんだけど。まぁVBではよく使われるようだしそう紛らわしくもないしいいかなと。
VBでグローバル変数はプログラムの何よりも最初で宣言すればいいらしい。
Dim ExpressionState As Integer
VBでは変数の宣言はDimで書く。BasicでDimといえば配列の宣言に使われるのが相場だが、配列の宣言にも使う。
Dim OperatorsName() As String
()を付ければ配列になる。()内に数字を書けば静的に確保されるが、これは後でSplitで得られた配列を入れるのでこれでいい。
ここでAs Integerと書いてるけど、これでInteger型でということを示している。
ちなみにVBのIntegerはVB.NETでは System.Int32、まぁC#で言うところのintと一緒だけど、VB6ではCで言うところのshortに相当する。
なので-32768~23767しか扱えない。なのでLongを使うことが推奨されている。とこれを書いてから知った。まぁそんな値は使わんからこのままでいいが。
ちなみにVB.NETでLongはSystem.Int64に相当するのでわけがわからない。Longを使うべしはVB6に対する言葉だ。
これでプログラムを書いていたのだが、なぜかフリーズしてしまうことがあった。
なんでだろとおもって調べていたら変数名を間違えてたようで。
というのもVBでは変数を宣言出来るけどオリジナルのBasic同様にスカラー変数は宣言せずに使うことが出来る。
宣言することが推奨されているけどチェックはしてくれない。チェックして欲しければ最初にこう書いておけばいい。
Option Explicit
ちなみにVB.NETではこれは標準で有効らしい。
ただ実行するまでエラーが出てこないのが難点ではある。VB6ではデバッグ時はインタプリタとして動作しているようで。
サブルーチンを定義しようと思って、こんな風に書いてみた。
Private Sub PutOperator()
If ExpressionState >= 3 Then
ExpressionState = 2
ElseIf ExpressionState = 1 Then
ExpressionState = 2
End If
End Sub
Private Sub Btn3()
PutOperator
End Sub
まぁSubで始めてEnd Subで終わると言うのはVBらしい話ではある。
それで呼び出す時ですが、PutOperator()と書いたらおかしいと言われる。
どうもPutOperatorと()を付けなければよかったのだがこのときには理由が分からなかった。
まぁともかくこう書いておけばうまく動いた。
返り値を出したい時はSubではなくてFunctionを使う。
Private Function InputToStr(ByVal Numeric As Double) As String
If Abs(Numeric) >= 100
InputToStr = Format(Numeric, "0.0e-0")
Else
InputToStr = CStr(Numeric)
End If
End Function
返り値をAsで書くのは相変わらず。引数はByValを付けなければ参照渡しになってしまうので、ByValを付けておく方が無難な気がする。
返り値は関数名に代入するというのはVerilogのFunctionみたいだな。まぁアリと言えばありだが。
返り値があるかないかでSubとFunctionを区別するというのはめんどくさいように見えて合理的かなとも思った。
Cでは返り値がないことをvoid型の返り値があると書いているけどどうにもいいわけがましい気がするし。
と、SubとFunctionで宣言が違うことには一定の理解を示したが……後に信じられないことを発見してしまった。
エラーを示すためにダイアログを出すことにしてこういうコードを書いた。
MsgBox("Error")
まぁこれはうまくいったのだが、ダイアログの種類を変えようとこう書いた。
MsgBox("Error",vbCritical,"電卓-エラー")
と思ったら = がないとか怒られる。なんでやねんと。
調べたら返り値を取る場合と取らない場合で使い方が違うらしい。
返り値を取る場合は()で囲まずに、
MsgBox "Error",vbCritical,"電卓-エラー"
と書くのが正しいらしい。実はさっきPutOperator()ではエラーが出てPutOperatorだとうまくいった理由もこれ。
MsgBox(“Error”) がうまくいったのは (“Error”)を先に解釈したからのよう。
VB.NETでは返り値がなくても()を付けてもかまわんようで。それが当然だと思ってたのだが。
ちなみに括弧を省略する以外に、Callを前に付けて、
Call MsgBox("Error",vbCritical,"電卓-エラー")
と書いてもうまく動く。
ともかく1日VB6を扱っていてなぜこうなるということばかりだった。
まぁ他にも気になるところはあったのだけど、エラー処理とか。まぁあれも不気味でしたね。
資料がVB6で作ってあるのでVB6で実習してもらうと最初に言われたけど、まぁ難儀やわ。
もう1人の実習生は、Cで記述できるマイコンのプログラムに分担させる部分を増やしてVBでの記述を簡素化しようと試みていた。
それはどうよとも思ったけど、確かにCの感覚でVBに触れると痛い目を見るなとも思った。