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

By: Hitoshi Fujii

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

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

1

その他

Position

480


プロパティが設定できたら保存しておきます。ツールバーの[すべて保存]ボタンをクリックして保存します。「OKCANCL1に名前をつけて保存」ダイアログボックスが表示されたら「FormPaintSize.pas」と名前をつけて保存します。

これで、サイズ変更ダイアログは完成ね。次はメニューから呼び出せば完成かな。

    サイズ変更ダイアログの値を取得する

バージョン情報ダイアログは「ShowModal」メソッドで表示できたけど、今度のサイズ変更ダイアログも同じでいいのかな?

高橋先生:表示するだけならそれでいいんだけど、今回は設定のダイアログボックスだったよね。サイズ変更ダイアログを閉じるボタンには[OK]ボタンと[キャンセル]ボタンがあった。[OK]ボタンを押したときに設定を有効に、[キャンセル]ボタンを押したときには設定を無効にしよう。モード付きでフォーム表示すると戻り値を持つことができる。戻り値をセットするところまでは、テンプレートを使ったので自動的に入ってくる。[OK]ボタンを押したときには「mrOK」が戻り値になるので、If文で調べよう。

ナッキー:テンプレートを使うと、いろいろなことが自動でされるのね。バージョン情報ダイアログは「ShowModal」メソッドの戻り値を調べなかったけど、今度は調べて見るのかあ。そのあと、幅や高さを設定すればいいのかしら?

高橋先生:幅や高さの値は、サイズ変更ダイアログにあったエディットのTextプロパティが、フォームを閉じても残っている。デフォルトでは、サブフォームが閉じても非表示になるだけなんだ。だからコンポーネントの値を調べることもできるよ。

ナッキー:フォームを閉じちゃったら、なくなるのかと思っていました。違うフォームにあるコンポーネントのプロパティも調べられるのなら設定も簡単ですね。

高橋先生:簡単といえばそうだけど、コンポーネントを参照するときフォーム名を入れるのを忘れないでね。

ナッキー:プロパティの値を見るのに、フォーム名も必要なんですか?

高橋先生:コードの中では、すべてのコンポーネントは、同じユニット内のフォームのメンバだってことが前提で、フォーム名を書かずにすんでいるんだ。違うユニットにあるフォームのメンバの場合は、そのことを書かないとわからないんだ。コードを書く前に、バージョン情報ダイアログでもしてもらったように、「ユニットの使用」ダイアログボックスで、uses節に「FormPaintSize」を追加することも忘れないでね。

それから、ペイントボックスのサイズを小さくしても、全体が白くて境界線がわからないのでsbxDrawスクロールボックスの「Color」プロパティを元の値「clBtnFace」に戻しておこう。


では、コードより先にスクロールボックスのプロパティ設定をします。画面上部の「FormDrawing」タブをクリックして、画面を切り替えます。フォームデザイナで「sbxDraw」を選択して、プロパティページで「表示」カテゴリの「Color」プロパティに「clBtnFace」を選択しておきます。これでペイントボックスとスクロールボックスの区別がしやくなります。

次に、uses節にユニットを追加します。FormDrawingユニットを表示していることを確認して、[ファイル(F)|ユニットを使う(U)...]メニューをクリックします。「ユニットの使用」ダイアログボックスの一覧から「FormPaintSize」を選択して、[OK]ボタンをクリックします。設定できたら、コードエディタで、実装部のuses節を確認します。太字部分が追加されています。

implementation
uses FormABOUT, FormPaintSize;
{$R *.dfm}

uses節にユニットが追加できたら、イベントハンドラを作成します。フォームデザイナでMainMenu1をダブルクリック、もしくはマウスの右ボタンクリックで[メニューデザイナ(Y)...]を選択します。メニューデザイナで、[編集(E)|サイズ変更(S)...]メニューを選択します。オブジェクトインスペクタ、イベントページで「入力」カテゴリの「OnClick」をダブルクリックします。幅と高さは変数に入れておくので、数値が入れられる変数を2つ用意しておきます。また、白く塗りつぶすため「クリア」メニューで使った「TRect」型の変数も用意します。コードエディタに切り替わったら、太字部分を追加します。

procedure TfrmMain.S2Click(Sender: TObject);
var
  intW: Integer;
  intH: Integer;
  r   :  TRect;
begin

end;

サイズ変更ダイアログをモード付きフォームとして表示して、戻り値が「mrOk」かどうか調べるIf文を記述します。そして、サイズ変更ダイアログで入力した幅と高さを、それぞれ変数に代入します。太字部分を追加します。

procedure TfrmMain.S2Click(Sender: TObject);
var
  intW: Integer;
  intH: Integer;
begin
  if frmSizeDlg.ShowModal = mrOk then
  begin
    intW := StrToIntDef(frmSizeDlg.edtWidth.Text, 640);
    intH := StrToIntDef(frmSizeDlg.edtHeight.Text, 480);
  end;
end;

次にビットマップオブジェクトを破棄して、変数に代入したサイズで作り直します。そして、ビットマップオブジェクトを白く塗りつぶします。太字部分を追加します。

procedure TfrmMain.S2Click(Sender: TObject);
var
  intW: Integer;
  intH: Integer;
  r   : TRect;
begin
  if frmSizeDlg.ShowModal = mrOk then
  begin
    intW := StrToIntDef(frmSizeDlg.edtWidth.Text, 640);
    intH := StrToIntDef(frmSizeDlg.edtHeight.Text, 480);
    if Assigned(bmpBuf) then
    begin
      FreeAndNil(bmpBuf);
    end;
    bmpBuf := TBitmap.Create;
    bmpBuf.PixelFormat := pf32bit;
    bmpBuf.SetSize(intW, intH);

    r.Left   := 0;
    r.Top    := 0;
    r.Right  := intW;
    r.Bottom := intH;
    bmpBuf.Canvas.Brush.Color := clWhite;
    bmpBuf.Canvas.FillRect(r);
  end;
end;

最後にペイントボックスのサイズを設定してから、ビットマップオブジェクトの内容を「Repaint」メソッドで描画します。フォームのタイトルバーには「無題」と表示します。保存メニューの「Enabled」プロパティを「True」に設定します。太字部分を追加します。

unit FormDrawing;

interface
(中略)
implementation

uses FormABOUT, FormPaintSize;
{$R *.dfm}

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

procedure TfrmMain.C1Click(Sender: TObject);
var
  r: TRect;
begin
  r.Left   := 0;
  r.Top    := 0;
  r.Right  := bmpBuf.Width;
  r.Bottom := bmpBuf.Height;
  bmpBuf.Canvas.Brush.Color := clWhite;
  bmpBuf.Canvas.FillRect(r);
  pbxDraw.Repaint;
  S1.Enabled := True;
end;

procedure TfrmMain.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  if MessageDlg('終了しますか?', mtConfirmation, [mbOK, mbCancel], 0) = mrOk then
    CanClose := True
  else
    CanClose := False;
end;

procedure TfrmMain.FormCreate(Sender: TObject);
begin
  preX := -1;
  preY := -1;
  bmpBuf := TBitmap.Create;
  bmpBuf.PixelFormat := pf32bit;
  bmpBuf.SetSize(640, 480);
end;

procedure TfrmMain.FormDestroy(Sender: TObject);
begin
//  ReportMemoryLeaksOnShutdown := True;

  if Assigned(bmpBuf) then
    FreeAndNil(bmpBuf);
end;

procedure TfrmMain.O1Click(Sender: TObject);
begin
  if OpenPictureDialog1.Execute then
  begin
    if Assigned(bmpBuf) then
      FreeAndNil(bmpBuf);
    bmpBuf := TBitmap.Create;
    bmpBuf.LoadFromFile(OpenPictureDialog1.FileName);
    bmpBuf.PixelFormat := pf32bit;
    pbxDraw.Width  := bmpBuf.Width;
    pbxDraw.Height := bmpBuf.Height;
    pbxDraw.Repaint;
    Caption := Application.Title + ' - ' + OpenPictureDialog1.FileName;
  end;
end;

procedure TfrmMain.pbxDrawMouseDown(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if GetKeyState(VK_LBUTTON) < 0 then
  begin
    pbxDrawMouseMove(Sender, Shift, X, Y);
    S1.Enabled := True;
  end;
end;

procedure TfrmMain.pbxDrawMouseLeave(Sender: TObject);
begin
  stbMain.Panels[0].Text := '';
  stbMain.Panels[1].Text := '';
end;

procedure TfrmMain.pbxDrawMouseMove(Sender: TObject; Shift: TShiftState; X,
  Y: Integer);
var
  w: Integer;
  c: TColor;
begin
  stbMain.Panels[0].Text := 'X = ' + IntToStr(X);
  stbMain.Panels[1].Text := 'Y = ' + IntToStr(Y);

  if GetKeyState(VK_LBUTTON) < 0 then
  begin
    if sbtnHoso.Down then
      w := 5
    else
      w := 20;

    c := shpColor.Brush.Color;

    pbxDraw.Canvas.Pen.Mode  := pmCopy;
    pbxDraw.Canvas.Pen.Width := w;
    pbxDraw.Canvas.Pen.Color := c;
    pbxDraw.Canvas.MoveTo(preX, preY);
    pbxDraw.Canvas.LineTo(X, Y);

    bmpBuf.Canvas.Pen.Mode  := pmCopy;
    bmpBuf.Canvas.Pen.Width := w;
    bmpBuf.Canvas.Pen.Color := c;
    bmpBuf.Canvas.MoveTo(preX, preY);
    bmpBuf.Canvas.LineTo(X, Y);
  end;

  preX := X;
  preY := Y;

end;

procedure TfrmMain.pbxDrawPaint(Sender: TObject);
begin
  pbxDraw.Canvas.CopyMode := cmSrcCopy;
  pbxDraw.Canvas.Draw(0, 0, bmpBuf);
end;

procedure TfrmMain.S1Click(Sender: TObject);
begin
  if SavePictureDialog1.Execute then
  begin
    bmpBuf.SaveToFile(SavePictureDialog1.FileName);
    Caption := Application.Title + ' - ' + SavePictureDialog1.FileName;
    S1.Enabled := False;
  end;
end;

procedure TfrmMain.S2Click(Sender: TObject);
var
  intW: Integer;
  intH: Integer;
  r   : TRect;
begin
  if frmSizeDlg.ShowModal = mrOk then
  begin
    intW := StrToIntDef(frmSizeDlg.edtWidth.Text, 640);
    intH := StrToIntDef(frmSizeDlg.edtHeight.Text, 480);
    if Assigned(bmpBuf) then
    begin
      FreeAndNil(bmpBuf);
    end;
    bmpBuf := TBitmap.Create;
    bmpBuf.PixelFormat := pf32bit;
    bmpBuf.SetSize(intW, intH);

    r.Left   := 0;
    r.Top    := 0;
    r.Right  := intW;
    r.Bottom := intH;
    bmpBuf.Canvas.Brush.Color := clWhite;
    bmpBuf.Canvas.FillRect(r);

    pbxDraw.Width  := intW;
    pbxDraw.Height := intH;
    pbxDraw.Repaint;
    Caption := Application.Title + ' - ' + '無題';
    S1.Enabled := True;
  end;
end;

procedure TfrmMain.shpColorMouseUp(Sender: TObject; Button: TMouseButton;
  Shift: TShiftState; X, Y: Integer);
begin
  if ColorDialog1.Execute then
    shpColor.Brush.Color := ColorDialog1.Color;
end;

procedure TfrmMain.X1Click(Sender: TObject);
begin
  Close;
end;

end.

[サイズ変更(S)...]メニューが完成したら、保存して実行します。ツールバーの[すべて保存]ボタンで保存して、[実行]ボタンで実行テストします。実行できたら「お絵かきソフト」の[編集(E)|サイズ変更(S)...]メニューをクリックして、サイズ変更ダイアログを表示します。縦横のサイズを「200」程度にして[OK]ボタンをクリックします。左上に白い四角が表示されます。

Hide image
07完成図

図07 完成図

ナッキー:これで、お絵かきソフトが完成なんですね。長かったけどいろんな色を使って遊べたので、楽しかったなぁ。

高橋先生:描画の部分はお絵かき以外には、使えないように思うかもしれないけれど、好きな場所に文字を書くのにも使えるんだよ。コンポーネントだと表示される位置が決まっていることが多いからね。描画以外にも使える機能が盛りだくさんだったね。ナッキーもよくがんばったと思うよ。

ナッキー:サブフォームが使えるようになったら、新しいプログラムを考えるのが楽しくなりますね。よいしょ、よいしょ。

高橋先生:ところで、なんで荷造りしているの?

ナッキー:え?春だから、ちょっと旅行にでも行こうかと。

高橋先生:Turbo Delphiの機能はまだまだ紹介したいんだよ。いっぱいあるんだから。勝手に行ってもらっちゃこまるな。

ナッキー:そうですかぁ?じゃあ、「これから春休みにしますので、よろしくお願いしまーす。4月にまた会いましょうねー。」

高橋先生:次は、データベースなんだ!けっこう大変なんだよー。あれ?もう行っちゃったの?戻ってきたら厳しくいくぞ!


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

Prev | Next | Index


Server Response from: ETNASC01