ナッキーの「Turbo Delphiはじめて奮戦記」 - 第8回 計算機でエラーチェック

By: Hitoshi Fujii

Abstract: 前回はひととおりの機能をつけましたが、エラーチェックなどを加えてプログラムの完成度を高めましょう。

Hide image
nacky75

ナッキー

前回でほとんどできているから、エラーチェックを加えるだけならきっと簡単ね。ちょっと加えるだけでグレードアップするなら楽勝だわ。

 

Hide image
takahashi75

高橋先生

今回紹介するエラーチェックを使いこなせるようになると、本格的なプログラミングにも挑戦できるね。簡単ではないけど、ここまで充分習得できたから、今回もがんばってね。

    例外処理ブロック

じゃあ、まずはじめに、いつものように前回のプロジェクトを開きましょう。Turbo Delphiを起動して、画面中央の「ホームページ」で「Calclator.bdsproj」を選択。もし一覧に表示されていなければ、ツールバーの[プロジェクトを開く(Ctrl+F11)]ボタンをクリックします。「プロジェクトを開く」ダイアログボックスから「Calclator.bdsproj」を探します。

エラーチェックということですが、どういうときにうまく計算できないかを考えないとね。思いつくところだけ箇条書きにしてみます。ボタンごとに分けて考えるといいんだって。

  • 1度計算結果を出したあと、クリアしないでテンキーボタンを押すとき
  • edtInput1に値が入っていないのに演算ボタンを押すとき
  • edtInput2に値が入っているのに演算ボタンを押すとき
  • 値が何も入っていないのに計算ボタンを押すとき
  • edtInput1だけに値が入っていて計算ボタンを押したとき

このくらいですよね、高橋先生。

高橋先生:もうひとつ加えて欲しいな。プログラムの中では0で割ることができないんだ。0を足す、引く、掛けるはOK。0で割ると実行時エラーになってしまう。実行時エラーがどんな表示になるか、見てみよう。


どれどれ。ツールバーの[実行]ボタンをクリックして、実行。edtInput1には好きな数字を入力して、[÷]ボタンをクリックします。次の数値はテンキーから「0」だけ入力します。

010割り

図01 0割り

[計算]ボタンをクリックすると、あ、エラーメッセージが表示されました。

Hide image
02デバッガ例外

図02 デバッガ例外通知

ナッキー:エラーメッセージが出るとドキドキして、つい[Enter]キーを押しちゃったり、適当にクリックしちゃったりするんです。

高橋先生:慌ててしまうことがあるよね。でもメッセージは大切な情報がかかれているから、難しかったとしても一応読んでね。また、設定によっては表示されないこともあるよ。このメッセージは「デバッガ例外通知」。Turbo Delphiの中でプログラムを動かしていて、エラーが出ると表示されるものだ。ユーザーがふだん使うときには見ることはないメッセージなんだ。メッセージボックスの右下の[ブレーク(B)]をクリックすると一時停止してコードを表示する。[継続(C)]ボタンをクリックすると、そのまま処理を進めるんだ。ここでは、[継続(C)]ボタンをクリックしよう。


それでは、[継続(C)]ボタンをクリックして続けます。メッセージボックスがもう一つ表示されます。

Hide image
03実行時エラーのメッセージ

図03 実行時エラーのメッセージ

高橋先生:もしも、[ブレーク(B)]ボタンをクリックしたら、一時停止してコードエディタが表示される。第4回 画面もコードもすっきりさせよう!で「デバッガの使い方-ブレークポイント」の説明をしたけど、ブレークポイントを設定したときと同じように止まるんだ。一時停止してしまっても、ツールバーの[実行]ボタンをクリックすれば、図03のメッセージボックスが表示されるから心配しないで。

こちらの2番目のメッセージボックスは、ユーザーが使うときも表示される。「0による浮動小数点除算.」って表示されても、よくわからないよね。[OK]ボタンをクリックしたらフォームに戻るよ。例外が発生した部分以降の処理はされないで、フォームに戻るんだ。そのまま値を入力しなおせば、計算しなおすこともできる。

ナッキー:こんなのが表示されたらどうしたらいいのかわかりません。それにフォームに戻っても困っちゃう。

高橋先生:実行時エラーがあっても、プログラムは動いたままなんだ。うまく続けられるよう変更しよう。変更は2つ。1つ目は入力をやり直せるように入力項目をクリアして、次の計算ができるようにする。2つ目はメッセージの内容をもっとわかりやすくするよ。

ナッキー:このメッセージボックスは、プログラマが表示しているのではなくて、Turbo Delphiが表示しているんですよね。それを変えちゃうことができるの?

高橋先生:例外処理ブロックを使って、Turbo Delphiのメッセージボックスは取り替えることができるんだ。先に例外の話をしよう。

ナッキー:「例外」って特殊な場合ってことですか?

高橋先生:プログラムを動かす上でのエラーをTurbo Delphiでは「例外」と呼んでいる。例外が発生すると、Turbo Delphiは、そのことをプログラマに伝えるために、例外オブジェクトを作っているんだ。例外オブジェクトにはいろいろな種類がある。例外オブジェクトは、例外の情報や、例外を取り扱う機能が入っているものだよ。例外の内容を示したメッセージも、例外オブジェクトの種類によって異なる。

ナッキー:例外はエラーなんだ。例外オブジェクトは、プログラマが例外を扱いたいときに使うものなのね。

高橋先生:「図02デバッガ例外通知」のメッセージを見てみよう。「例外クラスEZeroDivide(メッセージ:'0による浮動小数点除算.')を送出しました。」と表示されている。例外クラスは、例外オブジェクトの型を表している。つまり、例外オブジェクトの型が「EZeroDivide」ってことがわかる。

今回の例外オブジェクトは、Turbo Delphiが内部で自動的に作成したものだけど、プログラマが独自に例外を発生させたりできるんだ。

ナッキー:へえー、そうなんだ。でも、どうやって、発生した例外を使うことができるの?

高橋先生:そうだね。例外の発生を捕らえるには、例外処理ブロック「try...except文」を使うんだ。ここに、例外が発生したときの処理を書くことができる。使い方は

try
  //例外が発生するかもしれないコード①
  //続きのコード②
except
  //例外が発生したときのコード③
end;
//続きのコード④

例外が発生しないときは①、②の次は④の順で処理をする。例外が発生したときだけ、①、③、④の順で実行される。③のコードは例外が発生しなければ実行されないので気をつけて。

tryとexceptの間に0割りするかもしれない文を置いて、exceptからend;の間にメッセージボックスの表示と、入力値のクリアを行おう。

ナッキー:うーんと、0割りしそうなのは割り算の部分だけよね。if文の中にはどうやって書き加えるんですか?

高橋先生:if文の中にtry except文を書き込めるよ。注意して欲しいのはtry except文では例外が発生しても続きの処理をしてしまうんだ。処理をストップしてしまいたければ、Exitで抜けるようにしてね。

ナッキー:抜けるってどこに?

高橋先生:Exitを呼び出すと、そのプロシージャから抜けるんだ。だから、この場合は、イベントハンドラから抜ける。でも、処理を続けたくないんだったら、これでいいよね。


なるほど、分かったような分からないような。とりあえず、やってみるか。じゃあ、まずtry except文の部分だけ考えてみます。最初に入力項目をクリアするんだったっけ。エディットのクリアは、長さ0の文字列を代入するのね。

try
  Ans := Num1 / Num2;
except
  edtInput2.Text := '';
end;

次に、メッセージボックスを表示。メッセージの内容は「0による浮動小数点除算.」ではわからないので、「0で割ることはできません。クリアボタンをクリックするか、正しい値を入力してください。」にします。

try
  Ans := Num1 / Num2;
except
  edtInput2.Text := '';
  ShowMessage('0で割ることはできません。クリアボタンをクリックするか、正しい値を入力してください。');
  Exit;
end;

ナッキー:どう、あってる?

高橋先生:try except文はこれでいいから、if文の中に書き込んでいいよ。ただし、if文の中だからtry except文の末尾の「end」は「;」をつけないでね。


そっか、間違えないようにしないと。コードを記述します。画面をコードエディタに切り替えて、btnKeisanClickイベントハンドラで、割り算をしているif文を探します。「Ans := Num1 / Num2」の前に空白行を入れて「try」を記述。勢いあまって改行しちゃった。うげ、なんか変な表示が!! 教えて、高橋先生!

Hide image
04try文入力

図04 try文入力

高橋先生:ブロック補完が働いたんだね。tryで始まる文はtry except文のほかにtry finally文というのもあるんだ。今回は使わないから余計な部分は削除してね。


あーびっくりした。補完してくれるのは便利だけれど、予想外のこともしちゃうのね。では、気を取り直して、コードを入力します。太字部分を追加します。特にtry except文の「end」の後に「;」をつけないようにします。

procedure TfrmCalc.btnKeisanClick(Sender: TObject);
var
  Num1 : Integer;
  Num2 : Integer;
  Ans : Double;
begin
  Num1 := StrToIntDef(edtInput1.Text, 0);
  Num2 := StrToIntDef(edtInput2.Text, 0);
  if lblEnzan.Caption = '+' then
    Ans := Num1 + Num2
  else
  if lblEnzan.Caption = '-' then
    Ans := Num1 - Num2
  else if lblEnzan.Caption = '×' then
    Ans := Num1 * Num2
  else if lblEnzan.Caption = '÷' then
    try
      Ans := Num1 / Num2;
    except
      edtInput2.Text := '';
      ShowMessage('0で割ることはできません。クリアボタンをクリックするか、正しい値を入力してください。');
      Exit;
    end
  else
    Ans := Num1;
  edtInput2.Color := clYellow;
  edtKekka.Color := clWhite;
  lblEqual.Visible := True;
  edtKekka.Text := FloatToStr(Ans);
end;

できたら、ツールバーの[すべて保存]ボタンで保存して、[実行]ボタンで実行してみます。先ほどと同じように0で割るようにしてみましょう。前回と同じように「デバッガ例外通知」が表示されますので[継続(C)]をクリックします。次に表示されるメッセージが作成したメッセージなら成功ね。

Hide image
05メッセージ変更

図05 メッセージ変更

ナッキー:これで、エラーを制御したってことになるんですね。ちょっと難しかったけれど、なんだか本格的♪

    イベントハンドラの共有

次はエラーチェックをもう少し進めます。最初にあげたチェック項目から「1度計算結果を出したあと、クリアしないでテンキーボタンを押すとき」について考えてみよっ。まずは結果を表示しているかどうかを調べるんですよね。

高橋先生:テンキーボタンを押したとき、まだ計算結果をクリアしていなければedtKekkaエディットに文字が入っている。また、lblEqualラベルのVisibleプロパティがTrueになっていたね。どちらかをチェックすれば、結果表示中かどうかがわかる。今回はif文を使うから、TrueかFalseの結果が出るlblEqualのVisibleプロパティのほうがいいかな。もし結果を表示中なら、btnClearボタンのOnClickイベントハンドラを呼び出して、入力内容をすべてクリアすればいいよ。

ナッキー:結果を表示していれば、クリアボタンのイベントハンドラを使ってクリアするんですね。イベントハンドラの呼び出しってどうやるんでしたっけ?

高橋先生:前回やったところだよ、しょうがないな。書き方はこう

イベント名(Sender);

だよ。Senderはコンポーネント名を入力してもいいけど、一般的にはSenderパラメータを流用するんだったね。

ナッキー:そっか、思い出した。イベントハンドラが呼び出される原因を作ったコンポーネントが入ってるSenderをパラメータに使うんでしたね。


思い出したところで、コードを書いてみます。テンキーを押したところでチェックしたいのでsbtn1ボタンのOnClickイベントハンドラで挑戦。コードエディタで、sbtn1Clickを探します。エディットに値をセットする前にクリアのコードを書いたほうがいいんだって。「=」が見えていれば、計算結果が表示されているから、lblEqualのVisibleがTrueのときクリアボタンのイベントハンドラを呼ぶのね。beginの下に空白行を作って、太字部分を追加します。

procedure TfrmCalc.sbtn1Click(Sender: TObject);
begin
  if lblEqual.Visible then
    btnClearClick(Sender);

//  edtInput1.Text := edtInput1.Text + '1';

  if lblEnzan.Caption = '' then
    edtInput1.Text := edtInput1.Text + '1'
  else
    edtInput2.Text := edtInput2.Text + '1';
end;

これを残りのテンキーのボタン、全部にコピーするんですね。

高橋先生:イベントハンドラを共有してみよう。実は、1つのイベントハンドラを異なるコンポーネントや、異なるイベントで一緒に使うことが簡単にできるんだ。

ナッキー:わ、同じ処理をするときには便利~

高橋先生:設定方法は簡単だよ。フォームデザイナのオブジェクトインスペクタの[イベント]ページでイベントハンドラを設定する際、ダブルクリックではなくて右端のプルダウンボタンで共有したいイベントハンドラ名を選択する。

Hide image
06イベント共有

図06 イベントハンドラの共有

まずは、sbtn1Clickの処理をすべてのテンキーボタンで共有したいので、分かりやすい名前に変更しよう。イベントハンドラの名前変更は、オブジェクトインスペクタの[イベント]ページでできる。

Hide image
07イベントハンドラ名変更

図07 イベントハンドラ名の変更


イベントハンドラ名を変更します。フォームデザイナで、sbtn1ボタンを選択。オブジェクトインスペクタの[イベント]ページで「入力」の「OnClick」に「TenKeyClick」と入力します。変更を確認するため、入力した「TenKeyClick」の部分をダブルクリック。ちゃんと1行目のsbtn1ClickがTenKeyClickになっていますね。

procedure TfrmCalc.TenKeyClick(Sender: TObject);
begin
  if lblEqual.Visible then
    btnClearClick(Sender);

//  edtInput1.Text := edtInput1.Text + '1';

  if lblEnzan.Caption = '' then
    edtInput1.Text := edtInput1.Text + '1'
  else
    edtInput2.Text := edtInput2.Text + '1';
end;

次に残りのテンキーのイベントハンドラをすべて「TenKeyClick」に変更します。テンキーボタンを選択してオブジェクトインスペクタの[イベント]ページで「入力」の「OnClick」でプルダウンボタンをクリックして、「TenKeyClick」を選択します。

高橋先生:イベントハンドラを共有しちゃったけど、クリックするボタンごとに入力される数値が異なる点には注意してね。全部同じ処理にしちゃうと、どのキーを押しても同じ数値しか入らない。

ナッキー:そうか~、単純じゃなかったのね。

高橋先生:テンキーの処理みたいに、大枠は同じだね。クリックされたボタンによって、ちょっとだけ違う処理をするときには、Tagプロパティを使って区別するといいんだ。Tagプロパティはプログラマが識別に使う、見た目に影響のないプロパティ。SenderのTagプロパティを見れば、どの処理をすればいいか区別がつくわけだ。

ナッキー:Tagプロパティにテンキーの数字を入れておけば、どのキーが押されたか分かるって訳ね。

高橋先生:そういうこと。でも、TagプロパティはInteger型だから、表示用に文字列として扱うには、型変換しなきゃね。

ナッキー:型変換関数を使って、変換するんですよね。

高橋先生:覚えていたかな。Integer型からstring型に変換するので「IntToStr」関数だよ。テンキーの数値とTagプロパティの値をリンクさせればコードの中で使うことができる。イベントハンドラのSenderパラメータからTagプロパティを参照する。ほんとは、SenderがTSpeedButton型だと良かったんだけど、型が違うのでSenderも型変換が必要だね。変換には「as」演算子を使用するよ。

A := Sender as 型名;

A変数の型を、型変換する型名とそろえておいてね。今回はAをTSpeedButton型で用意します。

ナッキー:コンポーネントも型変換しちゃうんだ。

高橋先生:そうしないと、Tagプロパティは、TObject型のSenderのままでは参照できないからね。


Tagプロパティから設定します。フォームデザイナでsbtn1ボタンを選択してオブジェクトインスペクタの[プロパティ]ページで「その他」の「Tag」プロパティに「1」を入力します。同様にしてsbtn2には「2」のように、テンキーボタンすべてにTagプロパティを設定します。sbtn0は「0」のままでいいので変更しません。

sbtn1

カテゴリ名

プロパティ名

設定値

その他

Tag

1

sbtn2

カテゴリ名

プロパティ名

設定値

その他

Tag

2

sbtn3

カテゴリ名

プロパティ名

設定値

その他

Tag

3

sbtn4

カテゴリ名

プロパティ名

設定値

その他

Tag

4

sbtn5

カテゴリ名

プロパティ名

設定値

その他

Tag

5

sbtn6

カテゴリ名

プロパティ名

設定値

その他

Tag

6

sbtn7

カテゴリ名

プロパティ名

設定値

その他

Tag

7

sbtn8

カテゴリ名

プロパティ名

設定値

その他

Tag

8

sbtn9

カテゴリ名

プロパティ名

設定値

その他

Tag

9


次にコードを書き換えます。コードエディタでTenKeyClickイベントハンドラを探しましょう。Senderを型変換するためのTSpeedButton型の変数を1つと、Tagプロパティを型変換するstring型の変数を1つ宣言。太字部分を追加します。

procedure TfrmCalc.TenKeyClick(Sender: TObject);
var
  TenKey    : TSpeedButton;
  TenKeyNum : string;
begin
  ...
  ...
end;

変数の用意ができたら、型変換のコードを書きます。最後のエディットに「'1'」を代入している部分を、TenKeyNum変数を代入するように書き換えましょう。太字部分を記述します。

procedure TfrmCalc.TenKeyClick(Sender: TObject);
var
  TenKey : TSpeedButton;
  TenKeyNum : string;
begin
  if lblEqual.Visible then
    btnClearClick(Sender);

  TenKey := Sender as TSpeedButton;
  TenKeyNum := IntToStr(TenKey.Tag);

//  edtInput1.Text := edtInput1.Text + '1';

  if lblEnzan.Caption = '' then
    edtInput1.Text := edtInput1.Text + TenKeyNum
  else
    edtInput2.Text := edtInput2.Text + TenKeyNum;
end;

ナッキー:これ1つで10個のボタンが動くんですね。なんかすごーい。

高橋先生:イベントハンドラを共有したり、プロシージャでまとめておくと、プログラムを修正したり、再利用するときに簡単になるね。


保存して実行してみます。今までと同じように動けばOKですって。

    その他のエラーチェック

次は「edtInput1に値が入っていないのに演算ボタンを押すとき」を考えます。if文でメッセージボックスを表示すればいいような気がする。教えて、高橋先生!

高橋先生:ここでは、例外を自分で発生させてみよう。raise文を使えば、例外を発生させることができるんだ。if文だと、イベントハンドラ全体を、大きなif文で囲まなくちゃならない。そうするとわかりにくくなるから、例外でイベントハンドラを抜けた方がすっきりするよ。

ナッキー:えー、例外って自分でも作れたんですか?

高橋先生:例外の作り方はちょっと独特。raise文というのを使うよ。

raise Exception.Create('エラーメッセージ');

作るときはraiseではじめるよ。次のExceptionは例外の種類のひとつで、シンプルなタイプ。例外の種類を違うものに置き換えることもできる。上のコードでは「エラーメッセージ」というメッセージボックスを出して処理をストップする。ShowMessageとは、メッセージボックスにアイコンがついていることや、タイトルバーが違うことが異なっている。

ナッキー:こんな呪文で、メッセージの見た目が本格的になるんですね。


じゃあ、例外を作ってみます。呪文は、「raiseではじめて、Exception.Create」。コードエディタで、btnTasuClickイベントハンドラを探して、太字部分を追加します。

procedure TfrmCalc.btnTasuClick(Sender: TObject);
begin
  if edtInput1.Text = '' then
    raise Exception.Create('値を入力してから演算ボタンをクリックしましょう。');

  lblEnzan.Caption := '+';

  edtInput1.Color := clYellow;
  edtInput2.Color := clWhite;
end;

演算ボタンに関係するエラーチェックがもう1つあるけど…

えっと、「edtInput2に値が入っているのに演算ボタンを押すとき」。これは、edtInput2の値を消して入力しなおしてもらおうかな。

高橋先生:今回はそれでいいよ。長さ0の文字列を代入して値をクリアしよう。メッセージも出した方が親切だね。これは通常のメッセージボックスを出そう。

ナッキー:どうして、さっきのは例外のメッセージで、今回のは通常のメッセージなんですか?

高橋先生:例外を発生させると、あとの処理は行われない。さっきは、以降の処理をしたくなかったので、例外を発生させてメッセージボックスを出した。今回はメッセージを出したあとの処理を行いたいので通常のメッセージボックスだけにしたんだ。

ナッキー:edtInput2に値が入ってることは、どうやって判別するんですか?

高橋先生:「<>」は等しくない状態を表す。これを使ってif文を作って、空白文字列と同じじゃなければ… という比較をするんだ。

ナッキー:空白文字列は、’’ でしたよね。

高橋先生:そう、シングルクォーテーション2つ。


メッセージは「値を入力しなおしてください。」と出します。メッセージの前にedtInput2エディットの値をクリアしとかなくっちゃ。

procedure TfrmCalc.btnTasuClick(Sender: TObject);
begin
  if edtInput1.Text = '' then
    raise Exception.Create('値を入力してから演算ボタンをクリックしましょう。');
  if edtInput2.Text <> '' then
    edtInput2.Text := '';
    ShowMessage('値を入力しなおしてください。');
  ...
  ...
end;

保存して実行すると、あれ?いつも必ずメッセージが表示されるようになっちゃった。どこがおかしいのかな?

高橋先生: 実は、if文の中は1文だけって決まっているんだ。1文っていうのは「;」までってこと。if文の中の処理に複数の文を入れたい場合は、beginとendで囲もう。その間ならいくつでも文を追加できるよ。

if 条件文 then
begin
  //処理文1;
  //処理文2;
end;

beginとendでくくることを、「ブロック化」という。もしもelseが続く場合はendの後に「;」を入れないようにしてね。

if 条件文 then
begin
  //処理文1;
  //処理文2;
end //ここには「;」は入れない
else
begin
  //処理文3;
  //処理文4;
end; //ここには「;」を入れる


ではさっきの文を書き直しましょう。太字部分を追加します。

procedure TfrmCalc.btnTasuClick(Sender: TObject);
begin
  if edtInput1.Text = '' then
    raise Exception.Create('値を入力してから演算ボタンをクリックしましょう。');
  if edtInput2.Text <> '' then
  begin
    edtInput2.Text := '';
    ShowMessage('値を入力しなおしてください。');
  end;

  lblEnzan.Caption := '+';

  edtInput1.Color := clYellow;
  edtInput2.Color := clWhite;
end;

最後の「値が何も入っていないのに計算ボタンを押すとき」と「edtInput1だけに値が入っていて計算ボタンを押したとき」はStrToIntDefにしたのでどちらの場合も「0」が結果に表示されて問題がないので、そのままにします。保存して実行します。間違いがなさそうなら、ほかのbtnHikuClick、btnKakeruClick、btnWaruClickに、今追加した二つのif文をコピーしましょう。コードエディタでコピーして貼り付けます。太字部分を追加します。コード全体も合わせて確認します。

procedure TfrmCalc.btnClearClick(Sender: TObject);
begin
  edtInput1.Text := '';
  edtInput1.Color := clWhite;
  edtInput2.Text := '';
  edtInput2.Color := clYellow;
  edtKekka.Text := '';
  edtKekka.Color := clYellow;
  lblEnzan.Caption := '';
  lblEqual.Visible := False;
end;

procedure TfrmCalc.btnCopyClick(Sender: TObject);
begin
  edtKekka.SelectAll;
  edtKekka.CopyToClipboard;
  btnClearClick(Sender);
  edtInput1.PasteFromClipboard;
end;

procedure TfrmCalc.btnHikuClick(Sender: TObject);
begin
  if edtInput1.Text = '' then
     raise Exception.Create('値を入力してから演算ボタンをクリックしましょう。');

  if edtInput2.Text <> '' then
  begin
    edtInput2.Text := '';
    ShowMessage('値を入力しなおしてください。');
  end;

  lblEnzan.Caption := '-';

  edtInput1.Color := clYellow;
  edtInput2.Color := clWhite;

end;

procedure TfrmCalc.btnKakeruClick(Sender: TObject);
begin
  if edtInput1.Text = '' then
     raise Exception.Create('値を入力してから演算ボタンをクリックしましょう。');

  if edtInput2.Text <> '' then
  begin
      edtInput2.Text := '';
    ShowMessage('値を入力しなおしてください。');
  end;

  lblEnzan.Caption := '×';

  edtInput1.Color := clYellow;
  edtInput2.Color := clWhite;
end;

procedure TfrmCalc.btnKeisanClick(Sender: TObject);
var
  Num1 : Integer;
  Num2 : Integer;
  Ans : Double;
begin
  Num1 := StrToIntDef(edtInput1.Text, 0);
  Num2 := StrToIntDef(edtInput2.Text, 0);
  if lblEnzan.Caption = '+' then
    Ans := Num1 + Num2
  else if lblEnzan.Caption = '-' then
    Ans := Num1 - Num2
  else if lblEnzan.Caption = '×' then
    Ans := Num1 * Num2
  else if lblEnzan.Caption = '÷' then
    try
      Ans := Num1 / Num2;
    except
      edtInput2.Text := '';
      raise Exception.Create('0で割ることはできません。クリアボタンをクリックするか、正しい値を入力してください。');
    end
  else
    Ans := Num1;
  edtInput2.Color := clYellow;
  edtKekka.Color := clWhite;
  lblEqual.Visible := True;
  edtKekka.Text := FloatToStr(Ans);
end;

procedure TfrmCalc.btnTasuClick(Sender: TObject);
begin
  if edtInput1.Text = '' then
     raise Exception.Create('値を入力してから演算ボタンをクリックしましょう。');

  if edtInput2.Text <> '' then
  begin
    edtInput2.Text := '';
    ShowMessage('値を入力しなおしてください。');
  end;

  lblEnzan.Caption := '+';

  edtInput1.Color := clYellow;
  edtInput2.Color := clWhite;
end;

procedure TfrmCalc.btnWaruClick(Sender: TObject);
begin
  if edtInput1.Text = '' then
     raise Exception.Create('値を入力してから演算ボタンをクリックしましょう。');

  if edtInput2.Text <> '' then
  begin
    edtInput2.Text := '';
    ShowMessage('値を入力しなおしてください。');
  end;

  lblEnzan.Caption := '÷';

  edtInput1.Color := clYellow;
  edtInput2.Color := clWhite;
end;

procedure TfrmCalc.TenKeyClick(Sender: TObject);
var
  TenKey : TSpeedButton;
  TenKeyNum : string;
begin
  if lblEqual.Visible then
    btnClearClick(Sender);

  TenKey := Sender as TSpeedButton;
  TenKeyNum := IntToStr(TenKey.Tag);

  if lblEnzan.Caption = '' then
    edtInput1.Text := edtInput1.Text + TenKeyNum
  else
    edtInput2.Text := edtInput2.Text + TenKeyNum;
end;

コピーしたらそれほど大変ではなかったわね。保存して実行してみます。

  • 1度計算結果を出したあと、クリアしないでテンキーボタンを押すとき ⇒ 値をクリア
  • edtInput1に値が入っていないのに演算ボタンを押すとき ⇒ エラーを表示
  • edtInput2に値が入っているのに演算ボタンを押すとき ⇒ エラーを表示
  • 値が何も入っていないのに計算ボタンを押すとき ⇒ 計算結果に「0」を表示
  • edtInput1だけに値が入っていて計算ボタンを押したとき ⇒ edtInput1の値を計算結果に表示

これらの項目がすべて解決したか、チェックしてみよっと。

高橋先生:今回説明したイベントハンドラの共有を使えば、4つある演算ボタンの処理を一つにまとめることもできるはずだね。これは宿題にしておくから、時間があったら挑戦してみてね。

    実行ファイル

ちゃんと動いたからこれで完成ね。完成までの道のりは長かったなぁ。でもプログラミングしてるって感じのものができました。

高橋先生:この計算機プログラムは、すぐにほかのパソコンで動かすことができるんだ。

ナッキー:インストールとかするんですか?

高橋先生:作業はファイルをコピーするだけ。ためしにTurbo Delphiが動いてないところで計算機のプログラムが動くかチェックしよう。Turbo Delphiを終了させてプロジェクトの保存先をチェックして。デフォルトのまま保存していれば「マイドキュメント」の「Borland Studio Projects」フォルダで「Calclator.exe」を探そう。拡張子が表示されていない場合は図08のようなアイコンのついたファイルを起動してね。

Hide image
08アイコン

図08 アイコン

ほかのパソコンで使う場合は「Calclator.exe」だけをコピーすれば同じように動くよ。

ナッキー:「Calclator.exe」だけをコピーすればいいんだー。じゃあ、友達にも使わせてあげようかな。

高橋先生:今回のプログラムなら「Calclator.exe」をメールの添付ファイルで送れば使ってもらえるよ。USBメモリなど外部記憶媒体に保存して渡してもいいね。

ナッキー:ふーん。

高橋先生:ほかの総合開発環境では、こうはいかないんだよ。インストールするためのツール(インストーラ)が必要だったりして、けっこう面倒なんだ。

ナッキー:Turbo Delphiで作ったプログラムは、簡単にほかの人にも使ってもらえるってことですね。

高橋先生:ただしプログラムによっては、拡張子が「exe」のファイルだけじゃ動かない場合もあるから注意してね。


Turbo Delphiを[×]閉じるボタンなどで終了します。次にマイコンピュータのアイコンなどから「Calclator.bdsproj」を保存したフォルダの中を参照します。「Calclator.exe」を探してダブルクリックなどで起動してみます。エラーを起こしても、デバッガ例外通知は表示されません。

Hide image
09完成図

図09 完成図

ナッキー:エラーチェックだけで楽勝って思ったのに、新しいことがたくさん出てきて大変でした。

高橋先生:どれも知っているとプログラミングの幅が広がる項目ばかりだよ。特に例外処理ブロックは大切だね。Delphi言語でのエラー処理は、ほかの言語にない、特徴的な部分だ。エラーが出てもプログラムが止まらないんだよ。

ナッキー:へぇ。普通は止まるんですか?

高橋先生:プログラムが終了してしまうのが一般的。Delphi言語では止まらないし、例外処理ブロックで独自の処理を追加できるからプログラマには嬉しいよ。

ナッキー:まだ、その嬉しさは感じられませーん。でもだんだん本格的なプログラムになってきた感じがしますね。

高橋先生:ここまでだけでも随分たくさん紹介してきたね。次回はさらに、マウスや描画の処理に挑戦してみよう。

ナッキー:わあ、何かおもしろそう。でも、きっと難しいんですよね。ますます、がんばらなくっちゃ!



ナッキーの「Turbo Delphiはじめて奮戦記」

Prev | Next | Index


Server Response from: ETNASC03