
ナッキー |
占いプログラム楽しみだなぁ。占いとプログラミングと、どうやって結びつくんだろう?まだまだ、習わなくっちゃいけないことが、たくさんありそう。高橋先生、今回もよろしくお願いしまーす。 |
|
|

高橋先生 |
占いプログラムでは、血液型占いを作ってみよう。どんなふうにプログラムができていくか、その過程から考えてみてね。 |
|
|
プログラムを作るには
ナッキー:今回は占いのプログラム作るんですよね。どんなものを作るんですか? |
高橋先生:今回はどんなプログラムを作るかナッキーに考えて欲しいんだ。 |
ナッキー:えー、無理ですよ。こんなのを作るって言ってもらえれば、作れるけど。 |
高橋先生:順番に考えてみよう。そもそも占いをするには何が必要かな? |
ナッキー:う~ん。占い師さんと占いたい内容がわかればいいんじゃない。 |
高橋先生:占い師がすることは何?さらに占いたい内容を、血液型占いに絞ってみよう。 |
ナッキー:占い師さんは占ったことを話してくれますね。血液型占いだったら、A型の運勢や、B型の運勢なんかです。 |
高橋先生:そうだね。血液型占いならA型、B型、O型、AB型の血液型の運勢を占う。占い師は相手の血液型を聞いて占って、結果を話してくれる。もうちょっと整理すると、血液型を受け取る。次に占う。最後に結果を知らせる。プログラムっぽくいうと、血液型を入力して、占うっていう処理をして、結果を出力する。

図01 プログラムの流れ |
ナッキー:じゃあ、プログラムは血液型が入力できて、占って、結果が出力できればいいのね。 |
高橋先生:そのためには、どんな画面だったらいいと思う? |
ナッキー:血液型はボタンか、前回やった、リストボックスやオプショングループも入力できますね。結果はエディットかラベルで表示できそう。あ、はじめにやったメッセージボックスでも文字列を表示できます。 |
高橋先生:では、ボタンを使おう。結果はメッセージボックスでいいね。 |
ナッキー:「占う」というのが一番わからないんですが。 |
高橋先生:そこはまたあとで、ゆっくり教えましょう。最初は画面作成からね。 |
ナッキー:画面には、血液型のボタンが4つフォーム上にあればいいんですね。 |
|

図02 完成図
TGridPanelでレイアウト
プロジェクトを新規作成します。メニューバーの「ファイル(F)|新規作成(N)|VCLフォームアプリケーション-Delphi for Win32(V)」を選択。コンポーネントの配置より先にフォームのプロパティを設定しておきましょう。Turbo Delphi画面左下部の「オブジェクトインスペクタ|プロパティ」ページ「ローカライズ対象」の「Caption」プロパティに「血液型占い」と入力します。フォームに名前も付けておくんだって。「その他」の「Name」プロパティに「frmUranai」と入力します。
ボタンを使って血液型を入力することにしたけど、4つのボタンが必要なのね。きれいに並べるの難しいな。
高橋先生:たくさんあるコンポーネントを、きれいに並べるためのコンポーネントがあるんだよ。前回TPanelコンポーネントを使ったね。 |
ナッキー:Alignプロパティを設定して、フォームの上に広げたコンポーネントですね。 |
高橋先生:今回紹介するコンポーネントもTPanelコンポーネントと同じように上にコンポーネントを乗せられるコンポーネントなんだ。こういう上にコンポーネントを載せられるコンポーネントを「コンテナコンポーネント」と呼びます。 今回のコンテナコンポーネントはTGridPanelです。碁盤の目のようにコンポーネントを置く場所が確保されていて、そのマス目の上にコンポーネントを並べることができるんだ。TGridPanelの上にボタンを4つ配置してみてください。 |
|
自動で並べてくれるコンポーネントがあるのね。では、Turbo Delphi画面右下部ツールパレットの「Additional| TGridPanel」コンポーネントを1つ配置します。

図03 TGridPanel配置
GridPanel1を選択したまま、「オブジェクトインスペクタ|プロパティ」ページで設定を行います。「レイアウト」の「Align」プロパティを「alClient」に設定してください。GridPanel1がフォームいっぱいに広がります。さらに「ローカライズ対象」の「Caption」プロパティの内容を削除します。
次にボタンを配置しましょう。ツールパレットの「Standard|TButton」コンポーネントを4つ配置。TGridPanelのマス目1つに1つずつ配置します。
「オブジェクトインスペクタ|プロパティ」ページの「Caption」プロパティを、それぞれ「A型」「B型」「O型」「AB型」とします。順番は適当でいいみたいです。そういえば、Captionプロパティって、「ローカライズ対象」以外のところにもあるのを発見したけど、同じプロパティがいくつものカテゴリに表示されていることもあるんだって。たしかに、名前順にしておくと、Captionプロパティは一個だけしか表示されない。
それから、コンポーネントを呼ぶときに間違えやすいので、TButtonにNameプロパティをつけます。ボタンを1つ選択します。「オブジェクトインスペクタ|プロパティ」ページの「その他」の「Name」プロパティをCaptionプロパティに合わせて、それぞれ「btnA」「btnB」「btnO」「btnAB」としましょう。

図04 ボタン配置
ナッキー:このままだと、フォームのサイズ変更があったときはボタンの位置はどうなるんだろう?フォームのサイズを変更してみよう。位置関係は変わらないですね。 |
高橋先生:前回フォームのサイズ変更をしても、画面が崩れないようプロパティを工夫してもらったね。今回も気をつけてみよう。ボタンをフォームいっぱいに広げてみよう。ボタンのAlignプロパティを全部alClientにしてみて。 |
ナッキー:全部伸びてフォームに広がりました。ボタンがくっつきすぎじゃない。 |
高橋先生:ボタンに隙間を開けるプロパティがTGridPanelにあります。Paddingプロパティに数値を入れると、ピクセル単位で隙間を開けられます。 |
|
了解。では、プロパティを設定していきます。すべてのボタンを選択して「オブジェクトインスペクタ|プロパティ」ページで設定を行います。「Align」プロパティを「alClient」にします。ついでにボタンのFontプロパティも変更しちゃおう。ボタンをすべて選択したままプロパティページで設定を行います。「ローカライズ対象」の「Font」プロパティで[…]ボタンをクリックして、「フォント」ダイアログボックスを表示します。フォント名は日本語の名称が付いていて「@」が付いていないものであれば好きなものを選んでいいみたい。私は「MSPゴシック」というフォントを選んでいます。フォントサイズは「30」くらいにします。

図05 フォントダイアログボックス
次にTurbo Delphi画面左上部の構造ペインでGridPanel1を選択して、プロパティページの「レイアウト」の「Padding」プロパティで「+」をクリックします。「Bottom」「Left」「Right」「Top」それぞれにに「5」を入力しましょう。

図06 Paddingプロパティ
うまく隙間ができていないような場合は、フォームのサイズを少し広げればいいんだって。
少しは見やすくできたかな。

図07 画面完成
関数-Random関数
ナッキー:ボタンをクリックすると占い結果がでるようにするんですよね。いよいよ占いたいんですけど。 |
高橋先生:本日のラッキーアイテムがわかる、なんてどう? |
ナッキー:うわ、すっごい。ラッキーアイテムがわかる機能があるんですか?! |
高橋先生:…。そ、そういうのはないけど、ランダムな数値をくれる「関数」があるんだ。 |
ナッキー:え?関数って表計算ソフトに出てきたりしますよね。 |
高橋先生:たとえばAverage関数なら数値を3個入力するとその平均値を計算してくれる。パラメータになにか値を入れると計算して結果を戻してくれるのが関数です。使い方は 変数 := 関数名(パラメータ1,パラメータ2~); 大事な点は関数では中で計算した結果、値を持つということ。プロシージャのときは処理をして終わりだったから、あとのことは考えなくて良かった。関数の場合は変数やプロパティに代入したり、ほかの関数やプロシージャの引数パラメータとして使ったり、何らかの方法で値を使う必要があるんだ。 |
ナッキー:そっか、計算だけさせておいて知らんぷりしてちゃダメなのね。それで、どんな関数を使うんですか。 |
高橋先生:Random関数といいます。自分で乱数表のようなものを持っているんだよ。パラメータは「Integer」という整数型で、乱数の範囲がいくつまでかを指定できます。整数型は、小数点がつかない整数を代入できる型です。 A := Random(3); とするとAには0、1、2のどれかが代入されます。 |
ナッキー:パラメータに「3」と入れても、答えに「3」は出てこないんですか。0から3個分ってことで2までなんすね。このランダムな数と占いがどうつながるんですか? |
高橋先生:項目に上から順に番号をつけて、ランダムな数値が当たったものが、ラッキーアイテムってことにしたらどう?思いつく品目を5つ挙げてみて。なんでもいいよ。 |
ナッキー:携帯電話と、手紙、鍵、デジカメあとは大好きなチョコレートで5品目です。2番が当たればラッキーアイテムは「手紙」ってことなのね。 |
|
ランダムな値を取得しましょう。Random関数で得た値を一度変数に格納します。まずはbtnAのonClickイベントハンドラを作成しましょう。「オブジェクトインスペクタ|イベント」ページの「入力」の「OnClick」をダブルクリックして、イベントハンドラの枠を作成します。変数を宣言するときは「begin」の前に空白行を作って「var」を記述するんだったわね。次の行に変数名「Lucky_No」をInteger型で宣言します。太字部分を入力します。
procedure TfrmUrani.btnAClick(Sender: TObject);
var
Lucky_No : Integer;
begin
end;
btnAのOnClickイベントハンドラに続けて入力します。Lucky_No変数にRandom関数で得た結果を代入してっと。Random関数のパラメータは「5」です。太字部分を入力します。
procedure TfrmUrani.btnAClick(Sender: TObject);
var
Lucky_No : Integer;
begin
Lucky_No := Random(5);
end;
これで、ランダムな整数が1つ決まりました。
構文を使おう-case文
ナッキー:ランダムな数値は決まったから、これをif文で分岐させてメッセージを出すんですね。 |
高橋先生:第3回のとき、if文の中にたくさんif文を書いて、わかりにくくなったけど今回もそうする?今回は値を追加していくのではないから、変数を使ってもif文はすっきりしません。 if Lucky_No = 0 then
Lucky_Item := 'A'
else
if Lucky_No = 1 then
Lucky_Item := 'B'
else
…; |
ナッキー:「if Lucky_No = 0 then~」「if Lucky_No = 1 then~」とif文の中に入れるのではなくて、それぞれを独立させればいいんじゃないかな。 if Lucky_No = 0 then
Lucky_Item := 'A';
if Lucky_No = 1 then
Lucky_Item := 'B';
… |
高橋先生:それでも似たようなif文がたくさんできることには変わりないよ。ここであたらしい構文を紹介します。多分岐に使う「case」文です。1つの項目に関して「aのとき、bのとき~」というように複数に分岐して処理できます。書き方は case A of
1 : B := 10;
2 : B := 15;
3 : B := 20;
end; Aの値が1のとき、Bに10を代入します。Aの値が2のとき、Bに15を代入します。Aの値が3のとき、Bに20を代入します。条件には整数型か、「char」型という半角英数の文字が1つ入る型の値が使えます。 ここではLucky_Noを条件にして、0から4の場合について変数Lucky_Itemに品目を代入することにしましょう。 |
|
今回のように1つの数値で複数に分岐させるのに、ぴったりの構文があるのね。btnAのOnClickイベントハンドラを表示して、先に品目を入れる変数LucKy_Itemを宣言しておきましょう。型はstring型ね。太字の部分を追加します。
procedure TfrmUrani.btnAClick(Sender: TObject);
var
Lucky_No : Integer;
Lucky_Item : string;
begin
Lucky_No := Random(5);
end;
次にcase文を追加します。条件はLucky_No。1の時Lucky_Itemに「携帯電話」を代入する、のようにコードを書いていきます。品目にはみんなの好きなアイテムをいれればいいよね。
procedure TfrmUrani.btnAClick(Sender: TObject);
var
Lucky_No : Integer;
Lucky_Item : string;
begin
Lucky_No := Random(5);
case Lucky_No of
0 : Lucky_Item := '携帯電話';
1 : Lucky_Item := '手紙';
2 : Lucky_Item := '鍵';
3 : Lucky_Item := 'デジカメ';
4 : Lucky_Item := 'チョコレート♪';
end;
高橋先生:このコードだと、コンパイルが通らないな。case文には「end;」が必要なんだよ。「ブロック補完」という機能のおかげで「case」と記述したあと「end;」が自動的に入力されるようになっている。でもイベントハンドラの「end;」があるから、最後にcase文がくるときには間違って削除してしまいがちだね。コンパイルが通らないというのはもちろんなんだけど、イベントハンドラを追加しようとしてもうまく作ることができないよ。 |
ナッキー:へえ、忘れると結構面倒なのね。 |
|
では、「end;」を付けて記述しなおします。太字の部分を記述します。
procedure TfrmUrani.btnAClick(Sender: TObject);
var
Lucky_No : Integer;
Lucky_Item : string;
begin
Lucky_No := Random(5);
case Lucky_No of
0 : Lucky_Item := '携帯電話';
1 : Lucky_Item := '手紙';
2 : Lucky_Item := '鍵';
3 : Lucky_Item := 'デジカメ';
4 : Lucky_Item := 'チョコレート♪';
end; //このend;が大事
end;
最後にメッセージボックスを出します。表示内容は「A型のあなた、ラッキーアイテムは」とLucky_Item変数の内容です。太字の部分を追加します。
procedure TfrmUrani.btnAClick(Sender: TObject);
var
Lucky_No : Integer;
Lucky_Item : string;
begin
Lucky_No := Random(5);
case Lucky_No of
0 : Lucky_Item := '携帯電話';
1 : Lucky_Item := '手紙';
2 : Lucky_Item := '鍵';
3 : Lucky_Item := 'デジカメ';
4 : Lucky_Item := 'チョコレート♪';
end;
ShowMessage('A型のあなた、ラッキーアイテムは' + Lucky_Item);
end;
これで完成ねっ!保存して実行しよう。ツールバーの[すべて保存]ボタンをクリックして保存しましょう。ユニット名は「FormFortune」、プロジェクト名は「Fortune」とつけます(私は保存の仕方マスターしちゃったけど、やり方がよく分からないひとは、第2回の記事をもう一度復習してね!)。保存できたら実行です。ツールバーの[実行]ボタンをクリックします。フォームを表示したらA型のボタンをクリック!わぁ「A型のあなた、ラッキーアイテムは携帯電話」だって。何度かクリックしてみました。
「A型のあなた、ラッキーアイテムは携帯電話」(0の項目)
「A型のあなた、ラッキーアイテムは携帯電話」(0の項目)
「A型のあなた、ラッキーアイテムはチョコレート♪」(4の項目)
「A型のあなた、ラッキーアイテムは手紙」(1の項目)
となりました。[×]ボタンで終了します。
OnCreateイベントハンドラで前準備
ナッキー:もう一回実行してみよう。あ、また「携帯電話」だった。今度も同じ順番で項目が表示されます。終了して、起動しなおすと同じラッキーアイテムが出てくるみたい。 |
高橋先生:Random関数は乱数表を持っていて、そのうちの1枚から数値を順に渡してくれるんだけど、乱数表自体の順番はランダムじゃないんだ。 |
ナッキー:えーっじゃあ、毎回1枚目の乱数表を使って数値を渡してくれているってこと? |
高橋先生:そうなんだ。だから乱数表自体の順番をランダムにするっていうプロシージャがある。 Randomaize; パラメータはないのでカッコも省略。 |
ナッキー:プロシージャが乱数表をかき混ぜてくれるの? |
高橋先生:そうだね。そのかき混ぜてくれるのはプログラムが動いている間1回だけでいいんだ。最初にボタンを押す前ね。 |
ナッキー:クリックしたときそれが最初かどうか調べなくちゃダメね。 |
高橋先生:フォームを作る最初の1回目っていうイベントハンドラがあるから、そこに記述すればいいよ。 プログラムを動かすとき、今回のような前準備が必要な場合がある。それを初期処理といいます。フォームや、フォームに乗っているコンポーネントに関して初期処理をする場合は、フォームのOnCreateイベントハンドラで初期処理を行うのが一般的だね。このイベントはフォームを表示する直前に起こるイベントです。だからOnCreateの処理をやっている間はまだ画面上にフォームは表示していないよ。早速作成してみて。 |
|
フォームのOnCreateイベントハンドラを作成します。マウスでは選択しにくいので構造ペインでfrmUraniを選択して「オブジェクトインスペクタ|イベント」ページの「その他」の「OnCreate」をダブルクリックしてイベントハンドラを作成します。「Randomize」プロシージャを記述します。太字の部分を追加します。
procedure TfrmUrani.FormCreate(Sender: TObject);
begin
Randomize;
end;
作成できたら保存して実行してみます。ボタンを何度かクリックすると、さっきとは違う順番でラッキーアイテムが表示されます。

図08 メッセージ表示
プロシージャを作ってみよう
ナッキー:できたから、このコードを各ボタンのイベントハンドラにコピーしよっと。 |
高橋先生:それでもちゃんと動くけど、処理自体は同じものがいくつもできてしまう。表示したい血液型だけが違うんだ。似た処理がたくさんあるときは「プロシージャ」を作ってみよう。 ボタンにコードをコピーした場合を考えてみて。あとになってラッキーアイテムを変更することがあるかもしれない。4つのボタンにラッキーアイテムを設定するcase文があったら、4箇所変更する必要があるね。手間がかかることもあるけれど、変更し忘れてしまうことの方がより心配だね。 |
ナッキー:プロシージャって自分で作ったりできるものなんですか? |
高橋先生:決まりに従って書けば、イベントハンドラを作るのと、それほど違いはないよ。書き方の決まりは procedure プロシージャ名(パラメータ1:型名; パラメータ2:型名; ~); begin 処理 end; |
ナッキー:わぁ、イベントハンドラに似てますね。 |
高橋先生:プロシージャ名は変数名と同じ命名規則に従って付けて。パラメータは必要があれば何個でも設定できる。パラメータはプロシージャを使うところでセットしてもらう。パラメータの値はプロシージャ内で使うことができるよ。今回の場合は血液型がわかる何かがパラメータになります。記述する場所も大切だ。ボタンのOnClickイベントハンドラより上に記述してください。 |
ナッキー:はじめに作るのは、イベントハンドラ名とパラメータですね。 |
高橋先生:「A型のあなた」というメッセージもラッキーアイテムと同様case文で分岐させて、変数に代入しておこう。case文で分岐させるには、血液型情報が整数型で入ってきたほうが処理しやすい。 1 → A型 2 → B型 3 → O型 4 → AB型 としよう。早速作ってみて |
|
ちょっと難しそうだなぁ。とりあえずイベントハンドラみたいに枠だけ作ってみようっと。プロシージャ名は「ShowItem」で、パラメータは「Blood」をInteger型で作ります。
procedure TfrmUrani.FormCreate(Sender: TObject);
begin
Randomize;
end;
procedure ShowItem(Blood: Integer);
begin
end;
高橋先生:どこに記述するかも大切だよ。プログラムが動いているときはイベントの順番は関係ないけれど、コンパイルのときは上から順にチェックされる。まだ定義していないプロシージャを呼び出すことになってコンパイルエラーになってしまうんだ。こんなときはコードの中ほどあたりにある implementation {$R *.dfm} のすぐ下に作ったほうがいいな。ほかのイベントハンドラより上に記述してみよう。 |
|
コンパイルが通らないんじゃ仕方ないわね。場所を移動して「A型」などの血液型情報を入れる、「Blood_Type」変数も用意しよう。string型で用意します。太字部分を記述します。
implementation
{$R *.dfm}
procedure ShowItem(Blood : Integer);
var
Blood_Type : string;
begin
end;
次は、case文で分岐させて「Blood_Type」変数に血液型を格納!
procedure ShowItem(Blood : Integer);
var
Blood_Type : string;
begin
case Blood of
1 : Blood_Type := 'A型';
2 : Blood_Type := 'B型';
3 : Blood_Type := 'O型';
4 : Blood_Type := 'AB型';
end;
end;
ラッキーアイテム関連の「Lucky_No」変数、「Lucky_Item」変数の宣言と、Random関数、case文はbtnAからコピーして貼り付けます。コピーしたい文字列を選択して、キーボードの[Ctrl+C]キーでコピーできます。次に貼り付けたい部分をクリックしてキーボードの[Ctrl+V]キーで貼り付けができます。
血液型とラッキーアイテムが取得できたら、メッセージボックスに表示します。「Blood_Type」変数と「のあなた、ラッキーアイテムは」と「Lucky_Item」をつないでメッセージをつくります。太字部分を追加します。
procedure ShowItem(Blood : Integer);
var
Blood_Type : string;
Lucky_No : Integer;
Lucky_Item : string;
begin
case Blood of
1 : Blood_Type := 'A型';
2 : Blood_Type := 'B型';
3 : Blood_Type := 'O型';
4 : Blood_Type := 'AB型';
end;
Lucky_No := Random(5);
case Lucky_No of
0 : Lucky_Item := '携帯電話';
1 : Lucky_Item := '手紙';
2 : Lucky_Item := '鍵';
3 : Lucky_Item := 'デジカメ';
4 : Lucky_Item := 'チョコレート♪';
end;
ShowMessage(Blood_Type + 'のあなた、ラッキーアイテムは' + Lucky_Item);
end;
やっと完成かな。実行しよう。
高橋先生:プロシージャは作っただけでは動かないよ。血液型のボタンから呼び出そう。 |
|
そうだ、プロシージャって呼び出さなければだめだった。まずはbtnAのイベントハンドラからプロシージャの呼び出しは「プロシージャ名(パラメータ);」だったわね。A型だからパラメータは「1」よ。コードエディタでbtnAのOnClickイベントハンドラを探して、すでに入っているコードを変数宣言も含めてコメントにします。コメントの下にプロシージャ呼び出しを書きましょう。太字の部分を記述します。
procedure TfrmUrani.btnAClick(Sender: TObject);
//var
// Lucky_No : Integer;
// Lucky_Item : string;
begin
// Lucky_No := Random(5);
// case Lucky_No of
// 0 : Lucky_Item := '携帯電話';
// 1 : Lucky_Item := '手紙';
// 2 : Lucky_Item := '鍵';
// 3 : Lucky_Item := 'デジカメ';
// 4 : Lucky_Item := 'チョコレート♪';
// end;
// ShowMessage('A型のあなた、ラッキーアイテムは' + Lucky_Item);
ShowItem(1);
end;
ここまでが、うまくいくか試してみておこう。保存して実行ね。ツールバーの[すべて保存]ボタンをクリックしたあと[実行]ボタンをクリックします。
うまく動いたことを確認したら、ほかのボタンのイベントハンドラも作成しましょう。ツールバーの[フォーム/ユニット切り替え]ボタンで画面をフォームデザイナに切り替えます。btnBコンポーネントを選択して、イベントページの「入力」の「OnClick」イベントハンドラをダブルクリックします。作成したイベントハンドラに「ShowItem(2);」を記述します。同様にbtnOとbtnABのOnClickイベントハンドラを作成します。最終的にはこんなコードになれば完成。コメント部分は省略します。太字部分を記述します。
procedure ShowItem(Blood : Integer);
var
Blood_Type : string;
Lucky_No : Integer;
Lucky_Item : string;
begin
case Blood of
1 : Blood_Type := 'A型';
2 : Blood_Type := 'B型';
3 : Blood_Type := 'O型';
4 : Blood_Type := 'AB型';
end;
Lucky_No := Random(5);
case Lucky_No of
0 :