現在位置:

ナッキーの「Turbo Delphiはじめて奮戦記」 - 第14回 お絵かきソフトでサブフォーム

投稿者: : Hitoshi Fujii

概要: 前回はメニューからファイルを保存したり、開いたりできるようにしました。今回は異なるフォームを作って、お絵かきソフトから呼び出してみましょう。

Hide image
nacky75

ナッキー

今回はテンプラ揚げる…じゃなかった、テンプレートを使うんでしたよね。それを使うと、フォームが簡単に作れるみたい。どうやって使うのか、しっかり教えてもらおうっと。

 

Hide image
takahashi75

高橋先生

メインフォーム以外のフォームは「サブフォーム」っていうんだ。テンプレートを使って作るときは、形が限定されているから、何にでも使えるわけじゃない。それでもよければテンプレートは便利だね。


    バージョン情報ダイアログを作る

早速フォームを作るのかしら?フォームを作ってからメニューを実装するってこと?そうすると、完成まで、あとどれくらい作業があるのかな?教えて、高橋先生!

高橋先生:メニューで実装されていないのは[サイズ変更(S)...]メニューと[バージョン情報(A)...]メニューだけだね。簡単なのは[バージョン情報(A)...]メニューのほうだから、先に作ろう。作業はバージョン情報ダイアログを作成、[バージョン情報(A)...]メニューを実装、次にサイズ変更ダイアログを作成、[サイズ変更(S)...]メニューを実装すれば、完成だ。今回作るのは、フォームの中でもダイアログボックスという種類だよ。

ナッキー:いよいよ完成なのね。やったー。長い道のりだったけど、がんばった甲斐があったわぁ。

高橋先生:…まだ、できてないって。喜ぶのが早すぎるよ。まずはテンプレートを使ったダイアログボックスの作成方法を紹介しよう。テンプレートは「オブジェクトリポジトリ」に入っている。「新規作成」ダイアログボックスで、オブジェクトリポジトリの一覧から1つを選択して、[OK]ボタンをクリックしたら出来上がり。

ナッキー:前から聞こうと思っていたんですけど、「テンプレート」って何かしら?

高橋先生:テンプレートはひな型みたいなものだよ。テンプレートを使うと、ある程度できた状態からフォームなどの作成を始めることができる。コンポーネントも少し配置されているから、足りないコンポーネントを追加して、プロパティ設定すれば完成だ。また、付属のボタンコンポーネントをクリックすると、フォームが閉じることもある。このように機能まで付いていることもあるよ。

ナッキー:へぇ、コンポーネントやコンポーネントのイベントハンドラまでついているのね。

高橋先生:はじめから付属しているコンポーネントは削除してもいいし、ほかのコンポーネントを追加してもいいよ。イベントハンドラも独自に作ったら、そちらを優先する。今回、先に作るバージョン情報ダイアログは、コンポーネントをそのまま使うから削除しないでね。


コンポーネントまで配置してあるなんて便利ね。すぐに作ってみようっと。それには、まずプロジェクトを開きます。Turbo Delphiを起動して、画面中央の「ホームページ」で「Drawing.bdsproj」を選択。もし一覧に表示されていなければ、ツールバーの[プロジェクトを開く(Ctrl+F11)]ボタンをクリックします。「プロジェクトを開く」ダイアログボックスから「Drawing.bdsproj」を探します。

テンプレートを使ってバージョン情報ダイアログを作成します。ツールバーの[新規作成]ボタンをクリックして、「新規作成」ダイアログボックスを表示します。

Hide image
01新規作成

図01 [新規作成]ボタン

項目カテゴリで「Delphi ファイル」を選択し、表示されたアイコン一覧から「バージョン情報ダイアログ」を選択して[OK]ボタンをクリックします。

Hide image
02新規作成ダイアログボック

図02 新規作成ダイアログボックス

「バージョン情報ダイアログ」用のユニットのコードエディタが表示されますので、フォームデザイナに切り替えます。

わぁ。本当に画面ができているのね。バージョン情報ダイアログのコンポーネントは、テンプレートのものをそのまま使用して、プロパティだけ変更します。

AboutBox(フォーム)

カテゴリ名

プロパティ名

設定値

その他

Name

frmAboutBox


ProductName(ラベル 「製品名」)

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

お絵かきソフト


Version(ラベル 「バージョン」)

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

バージョン0.1


Hide image
03バージョン情報ダイアログ_

図03 バージョン情報ダイアログ

バージョン情報ダイアログが完成したら、保存します。ツールバーの[すべて保存]ボタンをクリックします。バージョン情報ダイアログのファイル名は「FormABOUT.pas」とします。

    バージョン情報ダイアログを呼び出す

「バージョン情報(A)...」メニューを実装するのよね。メソッドなんかを使えばすぐにできそうだけど、どうなんだろう?教えて、高橋先生!

高橋先生:そう簡単にはいかないんだ。FormDrawingユニットには、FormABOUTユニットのことがわからないからね。

ナッキー:わからないって、どういうことですか?

高橋先生:FormDrawingユニットにFormABOUTユニットのことが何も書かれていないということだよ。コンポーネントを使っても、Type節に自動的に登録されるし、宣言をしないと変数は使えない。同じように、ユニットでも「使いますよ」ということを、どこかに記述する必要があるんだ。

ナッキー:じゃあ、var節とか?

高橋先生:ユニット用は「uses節」だ。フォームのType節の上にあったと思うから、確認してみよう。コードエディタで、上のほうにあるよ。

uses Windows, SysUtils, Classes, Graphics, Forms, Controls, StdCtrls, Buttons, ExtCtrls;

これらは、主にコンポーネントを使うためにあるユニットだから、コンポーネントを配置したときに、自動的にuses節に追加される。

ナッキー:じゃあ、ここにFormABOUTユニットも追加すればいいのね。

高橋先生:だめだめ、特に必要がない場合は、ここには書かないで。

ナッキー:えーっ?uses節に書くって、言ってたのにー

高橋先生:説明すると、頭がグルグルすると思うけど聞く?

ナッキー:聞く、聞く、聞きます。

高橋先生:以前、「第9回お絵かきソフトをつくろう」でインターフェース部と実装部の話したよね。インターフェース部は、ほかのフォームからも参照できる部分。実装部は、ほかのフォームからは参照できない部分ということだった。このことが大前提。そして、さっき紹介したuses節はどこにあったと思う?

ナッキー:えーっと、たしかインターフェース部でしたよね。

高橋先生:そうだね。ということは、ほかのフォームから参照することができるuses節なんだ。ユニットの「UnitA」と「UnitB」と「UnitC」で紹介しよう。

unit UnitA;
interface
uses Windows, SysUtils, UnitB;
//UnitAでは、Windows, SysUtils, UnitBが使える
…
implementation
…

このコードをUnitCが参照すると、インターフェース部のuses節にあるWindowsユニットとSysUtilsユニット、UnitBのこともUnitCに筒抜けになるということになる。ここまではいい?

unit UnitC;
interface
uses UnitA;
//UnitCでは、Windows, SysUtils, UnitB, UnitAが使える
…
implementation
…

ナッキー:そうなんですか?インターフェース部のuses節に書くと、参照するUnitCにまで参照されちゃうんだ。

高橋先生:そういうこと。WindowsユニットとSysUtilsユニット、UnitBは、使っているUnitA以外に、UnitAを参照しているUnitCにも参照される。そのとき、参照されるのはユニットのインターフェース部だ。

ナッキー:実装部は参照されないんですものね。

高橋先生:ここまでのことを踏まえて、もしもUnitBがUnitAを参照したらどうなると思う?

unit UnitB;
interface
uses UnitA;
//UnitBでは、UnitA, Windows, SysUtils, UnitBが使える
…
implementation
…

ナッキー:うーん。WindowsユニットとSysUtilsユニット、UnitAが使えるようになる、でいいんじゃないのかな。

高橋先生:UnitAは、UnitBを参照していなかった?

ナッキー:参照していたけど、UnitBから参照しているんだからいらないんじゃないかな。

高橋先生:でも、参照しているよね。参照しようとするんだよ。そうすると、UnitBのインターフェース部のuses節にUnitAがあるから、UnitAを参照する。そして、UnitAはインターフェース部のuses節にUnitBがあるから、UnitBを参照する。またまた、UnitBは…

ナッキー:やっぱり、頭がグルグルしてきました。これじゃあ、参照が終わりになりません。

高橋先生:そうなんだ、参照が循環して終われないので、これを「循環参照」という。だからコンパイルが通らない。必要がある場合以外、インターフェース部のuses節には作ったユニットを追加しないほうがいい。

ナッキー:じゃあ、どこに書けばいいんですか?

高橋先生:実装部だよ。簡単な方法があるんだ。メニューバーの「ファイル(F)|ユニットを使う(U)...」をクリックすると、「ユニットの使用」ダイアログボックスが表示される。ここで、追加したいユニットを選択して[OK]ボタンをクリックすると、実装部にuses節が追加される。直接実装部にuses節を書いてもいいよ。

Hide image
04ユニットの使用ダイアログ

図04 ユニットの使用ダイアログボックス

ナッキー:なんだ、簡単な方法があるなら早く言ってくださいよ。あー頭がグルグルした。


循環参照はちょっと難しかったけれど、インターフェース部に闇雲に追加しちゃだめだってことはわかったわ。では、簡単な方法でuses節を追加します。画面上部の「FormDrawing」のタブをクリックして画面を切り替えます。表示はコードエディタのままでいいので、メニューバーの[ファイル(F)|ユニットを使う(U)...]をクリックします。「ユニットの使用」ダイアログボックスが表示されたら、「FormABOUT」ユニットを選択して[OK]ボタンをクリックします。実装部の1行目にuses節が追加されました。

implementation
uses FormABOUT;
{$R *.dfm}

これで、コードでフォームを表示することができるのね。

高橋先生:フォームを表示するときには「ShowModal」メソッドを使う。これは、モード付きでフォームを表示するメソッド。モード付きフォームの特徴は、表示したフォームが閉じるまで、ほかのフォームを手前に表示することはできないということだよ。

ナッキー:じゃあ、ShowModalメソッドを使うだけでいいんだ。


では、バージョン情報ダイアログを表示できるようにコードを記述します。フォームデザイナでMainMenu1をダブルクリック、もしくはマウスの右ボタンクリックで[メニューデザイナ(Y)...]を選択します。メニューデザイナで、[ヘルプ(H)|バージョン情報(A)...]メニューを選択します。オブジェクトインスペクタ、イベントページで「入力」カテゴリの「OnClick」をダブルクリックします。コードエディタに切り替わったら、太字部分を追加します。

procedure TfrmMain.A1Click(Sender: TObject);
begin
  frmAboutBox.ShowModal;
end;

コードの記述ができたら、保存して実行します。ツールバーの[すべて保存]ボタンで保存して、[実行]ボタンで実行テストします。メインフォームが表示できたら、メニューバーで[ヘルプ(H)|バージョン情報(A)...]メニューを選択します。これで、作成したバージョン情報ダイアログが表示できます。

Hide image
05バージョン情報ダイアログ

図05 バージョン情報ダイアログ表示

やりました!新しいフォームをちゃんと表示できたわ。あ、でも何にもコーディングしてないけど、[OK]ボタンをクリックしたらフォームが閉じちゃった。

高橋先生:テンプレートだから、あらかじめできているんだ。テンプレートのすべてのボタンが完成しているわけではないけれど、テンプレートをうまく使えば効率よくプログラムを作ることができるよ。もし独自の処理をしたいときには通常どおりにコードを書けばいいよ。


    サイズ変更ダイアログを作る

バージョン情報ダイアログは完成!この調子でサイズ変更ダイアログも作っちゃおう。

高橋先生:さすがに、バージョン情報ダイアログほど簡単には作れないな。でもテンプレートを使うよ。

ナッキー:じゃあ、ちょっとだけ難しくなるのね。

高橋先生:今度使うのは「標準ダイアログ(縦並び)」テンプレート。ボタン二つと飾り枠が付いている。サイズを設定したいのだから、ほかに幅と高さを入力できるエディットが必要だね。数値を入力してもらうときは、上下ボタンで数値の増減が制御できるといいね。それから、それぞれにラベルが付いていると親切だろう。

ナッキー:ちょっと待って。エディットもラベルも今までに出てきたけど、上下ボタンって何かしら?

高橋先生:小さな黒い三角の印が付いていて、[▲]で数が増えて[▼]で数が減るボタンだよ。数値を設定する場面では見たことがあるんじゃないかな?

ナッキー:あー、あるある。ん?でもエディットと上下ボタンって別なの?

高橋先生:そうなんだ。別のコンポーネントだよ。上下ボタンは「TUpDown」コンポーネントだ。その「Associate」プロパティに、関連させたいコンポーネントを登録して使うんだ。普通はエディットと組み合わせて使う。あとは、配置してもらってから説明するよ。


えー、なんかちょっと心配だけど、とにかく画面を作成するところから始めます。ツールバーの新規作成ボタンをクリックして、新規作成ダイアログボックスを表示します。項目カテゴリで「Delphi ファイル」を選択し、表示されたアイコン一覧から「標準ダイアログ(縦並び)」を選択して、[OK]ボタンをクリックします。画面をフォームデザイナに切り替えます。

わぁ、さっきのバージョン情報ダイアログとは違う画面が作成できました。枠飾りは「TBevel」コンポーネントっていうんですって。この中にTLabelとTEditを2つずつ配置します。画面右下のツールパレットの「Standard」カテゴリから「TLabel」と「TEdit」を上下に2つずつ配置します。さらにツールパレットの「Win32」カテゴリで「TUpDown」コンポーネントを探して、2つずつ配置します。TEditの右横あたりにそれぞれ適当に並べます。

TUpDownコンポーネントはそのままにしておいて、ほかのコンポーネントのプロパティを先に設定しておきます。

フォーム名には「OKCANCEL」の後ろに連番がついて、「OKCANCEL1」や「OKCANCEL2」となります。手順によって番号が異なりますが、ここでは「OKCANCEL1」として説明を進めます。


OKCANCL1(フォーム)

カテゴリ名

プロパティ名

設定値

その他

Name

frmSizeDlg

ローカライズ対象

Caption

サイズ変更


Label1(ラベル)

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption


Label2(ラベル)

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

高さ


Edit1(エディット)

カテゴリ名

プロパティ名

設定値

その他

Name

edtWidth


Edit2(エディット)

カテゴリ名

プロパティ名

設定値

その他

Name

edtHeight


Hide image
06サイズ変更ダイアログコン

図06 サイズ変更ダイアログコンポーネント配置

あとは、TUpDownコンポーネントね。さっそく教えてもらおう。

高橋先生:ここで、TUpDownコンポーネントの「Associate」プロパティを設定してもらう。すると、関連付けるコンポーネントの高さに合わせて、隣にぴったりくっつくんだ。

ナッキー: Associateプロパティに設定するだけで、サイズ変更と配置までしてくれるんですね。それなら簡単だわ。

高橋先生:注意してほしい点が3つある。まず、1つ目。外観は1つのコンポーネントになったように見えるけれど、あくまで2つのコンポーネントだから気をつけてね。エディットと関連付けても、エディットを移動したときに一緒には移動してくれない。そういうときは、複数選択で移動してみよう。

2つ目の注意点。たとえばエディットと関連付けたとき、エディットのTextプロパティの値が「0」になる。実行中に上下ボタンをクリックすることで、エディットのTextプロパティの値が増減する。Textプロパティの数値とTUpDownコンポーネントの「Position」プロパティの値がリンクするようになっている。しかし、エディットはあくまでエディットなので、半角数値以外の値も受け付けてしまうんだ。そのため、今回はTextプロパティの値を使って、「StrToIntDef」関数で数値に変換できない値のデフォルト値をもたせよう。

3つ目の注意点。TUpDownコンポーネントには最大値が「100」と最小値が「0」がデフォルト値になっている。範囲が狭いので、使うときに適当な範囲に設定しなおす必要がある。最大値は「Max」プロパティ、最小値は「Min」プロパティで設定できるよ。

ナッキー:うーん。1つのコンポーネントに見えるけど、別々のコンポーネントってことね。それにみかけが変わっても、コンポーネントの性質が変わるってわけじゃないんですね。


では、プロパティを設定します。フォームデザイナの画面でUpDown1コンポーネントを選択します。画面左下のプロパティページで「リンク」カテゴリ、「Associate」プロパティの[▼]プルダウンボタンをクリックして「edtWidth」を選択します。edtWidthのTextプロパティが「0」に変わって、UpDown1が右隣に並んで配置されました。ほかにMaxプロパティとMinプロパティを設定します。最大値は「640」、最小値は「1」にしておきます。初期値としてPositionプロパティに、幅を「640」、高さを「480」とします。

UpDown1(上下ボタン)

カテゴリ名

プロパティ名

設定値

リンク

Associate

edtWidth

その他

Max

640

その他

Min

1

その他

Position

640


UpDown2(上下ボタン)

カテゴリ名

プロパティ名

設定値

リンク

Associate

edtHeight

その他

Max

480

その他

Min