1ウインドウの配置
1.1ウインドウの配置
今回は、前回と同じように、視覚的に配置する機能を使ってウインドウを作ってみます。
メニューの「編集」の「新しいファイルを追加」をクリックして、「ウインドウ」を選び、ファイル名を「wnd_calc」として追加してください(図1-1)。
前回と同様の操作で、ウインドウを作ります(図1-2)。
「Edit」コントロールを1個、「Btn」コントロールを16個配置し、位置を表1-1のように設定しています。
コントロール名 | 位置 |
---|---|
wndMain | 0 × 0 - 195 × 220 |
edit1 | 10 × 10 - 175 × 19 |
btn1 | 10 × 35 - 40 × 40 |
btn2 | 55 × 35 - 40 × 40 |
btn3 | 100 × 35 - 40 × 40 |
btn4 | 145 × 35 - 40 × 40 |
btn5 | 10 × 80 - 40 × 40 |
btn6 | 55 × 80 - 40 × 40 |
btn7 | 100 × 80 - 40 × 40 |
btn8 | 145 × 80 - 40 × 40 |
btn9 | 10 × 125 - 40 × 40 |
btn10 | 55 × 125 - 40 × 40 |
btn11 | 100 × 125 - 40 × 40 |
btn12 | 145 × 125 - 40 × 40 |
btn13 | 10 × 170 - 40 × 40 |
btn14 | 55 × 170 - 40 × 40 |
btn15 | 100 × 170 - 40 × 40 |
btn16 | 145 × 170 - 40 × 40 |
多いですが、規則的です。 「Btn」を1列だけ配置してから、それを4回コピー&ペーストして4行並べると早く配置できます。
配置できたら、「Btn」を1つずつ選択して「プロパティの編集...」ボタンを押し、「text」の項目に表1-2のテキストを設定します。
コントロール名 | 「text」の値 |
---|---|
btn1 | 7 |
btn2 | 8 |
btn3 | 9 |
btn4 | / |
btn5 | 4 |
btn6 | 5 |
btn7 | 6 |
btn8 | * |
btn9 | 1 |
btn10 | 2 |
btn11 | 3 |
btn12 | - |
btn13 | 0 |
btn14 | . |
btn15 | = |
btn16 | + |
以上で見た目が出来上がりました。 Kuinエディタ上部の「コードを表示」を押すと、自動生成されたプログラムが確認できます。 「show」と「close」という関数が生成されています。 そこで、Kuinエディタの右にあるファイル一覧から「\main」を選び、今作ったウインドウを表示させるプログラムを書きます(図1-3)。
2行目と5行目で、自動生成された「\wnd_calc@show()」と「\wnd_calc@close()」を呼んでいます。 実行すると、電卓らしい見た目のウインドウが表示されました(図1-4)。
1.2ボタンの押下イベント
今は実行中にボタンを押しても何も起こりませんので、ボタンが押されたら「Edit」コントロールに文字が入力されるようにします。
Kuinエディタ右のファイル一覧から「\wnd_calc」を選び、「デザイナを表示」を押して配置画面に戻します。 Kuinエディタ左のコントロール一覧から「btn15」と「edit1」以外を選びます(図1-5)。
「Shift」キーを押しながらクリックするとまとめて選択でき、「Ctrl」キーを押しながらクリックすると1つずつ選択状態が切り替えられますので、活用すると早く選択できます。
このまま「プロパティの編集...」を押し、「onPush」の項目に「\main@btnOnPush」と書き込みます。 「onPush」にはボタンが押されたときに呼び出す関数が設定でき、今回は「\main」ファイルの「btnOnPush」関数を呼び出すようにしています。
設定できたらファイル一覧から「\main」を選び、図1-6のプログラムを追加します。
ボタンが押されると、8から10行目のbtnOnPush関数が呼ばれます。 そこでbtnOnPush関数の行頭に「+」を書いて、他のソースファイルから呼び出せるようにしておきます。
btnOnPush関数の引数「btn」には、押されたボタンのインスタンスが入っており、この「btn」に設定されているテキストを、9行目で「edit1」のテキストに追加しています。
実行すると図1-7のように、ボタンを押すと数式が入力できます。
2電卓の計算
2.1逆ポーランド記法
ここからは、「=」のボタンを押したときの計算処理に取りかかります。
ファイル一覧から「\wnd_calc」を選び、「btn15」を選んで「プロパティの編集...」を押し、「onPush」の項目に「\main@btnEqualOnPush」と書きます。
ファイル一覧から「\main」を選び、長いですが図2-1を追加します。
14から21行目までのbtnEqualOnPush関数が、「=」ボタンが押されたときの処理です。
15から20行目までの「try」「catch」「end try」は、例外(エラー)を処理する構文です。 try文では、「try」から「catch」までが順番に処理されていき、その途中で例外が発生すると「catch」から「end try」までが実行されます。 例外が発生しなければ「catch」から「end try」まではスキップされます。
try内の16、17行目では、数式を「@parse」して「@calc」したものをEditコントロールに表示しています。 この@parse関数で数式を解析し、@calc関数で実際に計算する予定です。 途中で例外が発生すると、19行目で「Error」と表示されます。
23から61行目が@parseの中身で、このあと詳しく説明しますが、数式を解析しています。 63から65行目の@calcでは、解析した数式を計算する予定ですが、今は単に「join」メソッドにより、スペース区切りで文字列を連結しているだけです。
ちなみに1行目では、発生させる例外のコード「0x0001」を「excptCalcErr」という名前で別名定義しています。 0x0001と直接書いても良いですが、プログラムが読みにくくなるため、このように「const」文で別名を定義すると便利です。
2.2数式の解析
それでは@parse関数の中身を説明します。
例えば「2-3*4*5」という数式の場合、足し算より掛け算を先に計算するルールがあるため、最初に「3*4」を計算しなければなりません。 これは複雑なため、計算の順番を考慮して数式を並べた「逆ポーランド記法」という表記にいったん変換することを考えます。
「2-3*4*5」を逆ポーランド記法で書くと、「2 3 4 * 5 * -」となります(図2-2)。
つまり、計算の順番を表した木構造を作り、その木構造をたどりながら折り返すときにノードを拾っていったものが逆ポーランド記法になります。 逆ポーランド記法になっていれば、先頭から順番に読んでいって、「+」や「*」などの演算子が現れるたびに計算すれば正しい結果が得られるため便利です。
今回は数式から逆ポーランド記法に変換する方法として、「操車場アルゴリズム」という手法を使っています。 操車場アルゴリズムとは、演算子をスタックに溜めていき、それらよりも優先順位が低い演算子が現れたらスタックから取り出して出力する手法です。
ではもう一度@parse関数の中身を再掲します(図2-3)。
2、3行目で出力用のリスト「output」と、演算子を一時的に格納するスタック「tmp」を作成しています。 4行目のnumBufは、数値を格納するバッファです。
5から19行目で数式を1文字ずつ解析しています。 数値の場合は、例えば「12」という数が「1」と「2」に分かれないように、numBufにいったん溜めてから11行目や21行目でoutputに出力します。 演算子の場合は29行目の「priority」関数で優先順位を求めてから、スタック内よりも低い優先順位の演算子が現れたらスタックから取り出して、15行目や25行目で出力しています。 処理が終わったら27行目で、出力リストを配列に変換して返しています。
実行して「2-3*4*5」と入力して「=」ボタンを押すと、逆ポーランド記法に変換された「2 3 4 * 5 * -」が出力されます(図2-4)。
2.3数式の計算
最後に、得られた逆ポーランド記法の数式を、計算しましょう。 @calc関数の中身を図2-5のように書き換えます。
float型で計算しても良いですが、電卓は計算精度が高いほうが望ましいため、100桁の小数が扱える「num@BigFloat」型を使います。
2行目でこの「num@BigFloat」型の値が入るスタック「nums」を作成し、3から30行目までで逆ポーランド記法の数式を順番に解釈しています。
数値が来たら25から27行目のように「nums」のスタックに追加します。 「+」「-」「*」「/」が来た場合は5から24行目のように、numsから2つ値を取り出して各演算を行い、結果をnumsに戻します。 これを繰り返すと、最後に計算結果がnumsに残ります。
処理が終わったら33行目で、numsに残った計算結果を返しています。 実行して「2-3*4*5」と入力し「=」を押すと、正しく「-58」という結果が表示されました(図2-6)。
以上で電卓アプリの完成です。 次回は、3Dゲームを作ります。