ナッキーの「Turbo Delphiはじめて奮戦記」 - 第12回 お絵かきソフトにメニューバー追加

By: Hitoshi Fujii

Abstract: 前回はPenプロパティの設定と、ダイアログボックスを紹介しました。今回はさらにメニューやステータスバーを作ってみましょう。

Hide image
nacky75

ナッキー

お絵かきソフトに色が付いて、それらしくなってきました。今回はメニューバーとかを作るんですって。なんだか難しそうだけれど、これも簡単にできちゃうのかしら?

 

Hide image
takahashi75

高橋先生

心配しないで大丈夫。コンポーネントからメニューを作って、ますます本格的な外観にしてみよう。


    ステータスバー

「ステータスバー」から追加します。ステータスバーは通常、画面の下のほうに配置してあって、画面の状態などの情報を表示する部分なんですって。「お絵かきソフト」では何を表示するのかな?

高橋先生:今回はマウスポインタの位置を表示しよう。ペイントボックスの左上を「0,0」として、ピクセル単位で表示する。

ナッキー:表示するものは、わかりました。ステータスバーはどうやってつけるんですか?

高橋先生:「TStatusBar」コンポーネントを配置するんだよ。その中に、マウスポインタの位置を表示するための領域も追加しよう。マウスの右ボタンをクリックして、表示されたメニューの「パネルの設定(P)...」をクリックすると、「パネルの設定」ダイアログボックスが表示される。この「パネルの設定」ダイアログボックスで表示用の領域(パネル)を作ってもらうんだ。

完成画面はこんな感じかな?

Hide image
01ステータスバー

図01 ステータスバー

ナッキー:ちょっと難しそうだけど、とにかく挑戦してみます。


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

画面右下のツールパレット「Win32」カテゴリの「TStatusBar」コンポーネントを探して、フォーム上の適当な位置に配置します。デフォルトのAlignプロパティが「alBottom」なので、パネルか、スクロールボックスの下のほうに配置しています。スクロールボックスの方に配置した場合は、フォーム上にステータスバーが見えないので注意してくださいって、高橋先生が言ってました。ステータスバーをフォームに配置したいので、構造ペインで位置を変更します。構造ペインの「Panel1」か「sbxDraw」の下にある「StatusBar1」を「frmMain」の上にドラッグで移動します。移動できたらステータスバーのNameプロパティを設定します。StatusBar1コンポーネントを選択していることを確認します。オブジェクトインスペクタ、プロパティページの「その他」カテゴリで「Name」プロパティを探します。右側の入力欄に「stbMain」と入力します。

次に表示用パネルも作ります。stbMain ステータスバーコンポーネントの上で、マウスの右ボタンをクリックして「パネルの設定(P)...」を選択します。この「パネルの設定」ダイアログボックスで、ツールバーの[新規追加(Ins)]ボタンをクリックして、表示用パネルを3つ作成します。

Hide image
02パネル設定

図02 パネルの設定

追加できたら、幅を調整するためにプロパティを設定します。「パネルの設定」ダイアログボックスで「0 - TStatusPanel」を選択します。オブジェクトインスペクタ、プロパティページの「レイアウト」カテゴリで「Width」プロパティに「100」を入力します。次に「1 - TStatusPanel」を選択して、「レイアウト」カテゴリの「Width」プロパティに「100」を入力します。ここまで設定できたら「パネルの設定」ダイアログボックスは閉じます。

Hide image
03ステータスバーの追加

図03 ステータスバーの追加

これで、ステータスバーが作成できました。ここにマウスポインタの位置を表示するんですよね。ペイントボックスの上での位置を表示するんだから、ペイントボックスのイベントで記述すればいいのよね。高橋先生。

高橋先生:そうだね、pbxDrawペイントボックスコンポーネントのイベントでいいよ。マウスの動きにあわせるからpbxDrawの OnMouseMoveイベントだね。

ナッキー:マウスの位置はどうやって代入するんですか?

高橋先生:マウスの位置はOnMouseMoveイベントのパラメータ、「X」と「Y」に入ってくる。代入先はステータスバーに作った表示用パネルの「Text」プロパティにしよう。表示パネルは3つあったけど、それぞれ番号が付いている。「Panels」の「0」番、「Panels」の「1」番のように区別しているんだ。このように1つの名前に番号をつけて区別するような値を「配列」という。番号の方は「添え字」とか「要素番号」と呼ぶよ。コード上で、添え字は「[]」(角カッコ)で囲んで

StatusBar1.Panels[0]

のように記述する。このTextプロパティだから

StatusBar1.Panels[0].Text

となる。上からの位置に「'X = '」、左からの位置に「'Y = '」とつけよう。

ナッキー:え?つまり表示枠のTextプロパティが「配列」ってことなんですか?

高橋先生:そうじゃなくて、表示用パネル自体が配列なんだ。配列っていうのは1個の値ということもあるけれど、プロパティだったりコンポーネントだったりすることもある。今回はPanelsプロパティが配列だったんだ。

ナッキー:なんとなくは、わかりました。今回は3つ作ったけれど、そのうちの2つに文字を表示するんですね。

高橋先生:そうだね。添え字は「0」と「1」の2つだよ。自分で作るときは、添え字を好きな数値からはじめることができるけど、普通は「0」番目から数える。

今回は使わないけれど、自分で配列の変数を宣言するときは、通常の宣言と違うから紹介しておこう。

var
  a : array [1..12] of Integer;

「array」の後に、添え字の「始まりの番号..終わりの番号」を「[]」(角カッコ)でくくって表す。そして、添え字のあとに「of」と型名をかいて配列を宣言する。これでa[1]からa[12]までの異なる変数が用意できるんだ。

ナッキー:普通の宣言とは全然違いますねぇ。

高橋先生:マウスがペイントボックスから出たら、マウスの位置は表示しない方がいいね。表示枠に「''」(長さ0の文字列)を代入しておこう。

ナッキー:「ペイントボックスから出たら」ってどんなときですか?

高橋先生:ちゃんとペイントボックスに「OnMouseLeave」っていうイベントがあるから、簡単だよ。


本当に簡単なのかな?先にマウスポインタの位置を表示します。画面をコードエディタに切り替えます。コードエディタでpbxDrawMouseMoveイベントハンドラを探します。マウス位置は「X」パラメータ、「Y」パラメータに入ってきますが整数型なので、文字列型でステータスバーに表示するには型変換が必要なんですって。型変換は「第7回 計算機に機能追加」で紹介してあったなぁ。型が異なるプロパティや変数に代入するとき、関数を使って型を変更しちゃうんだったわね。今回は「IntToStr」でInteger型をstring型に型変換します。それぞれの値の前に「'X = '」と「'Y = '」をつけます。代入先はステータスバーの「Panel[0].Text」プロパティと「Panel[1].Text」プロパティです。太字部分を追加します。

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;

次にペイントボックスからマウスが離れたとき、ステータスバーを空にします。画面をフォームデザイナに切り替えます。フォーム中央のペイントボックスを選択します。オブジェクトインスペクタ、イベントページで「入力」カテゴリの「OnMouseLeave」をダブルクリックします。ステータスバーの2つのパネルに「''」を代入。太字部分を追加します。

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

高橋先生:コードが記述できたら、マウスポインタの形を変更してみよう。プロパティ設定で、簡単に変えられるよ。

ナッキー:マウスポインタの形って変更できるんですね。

高橋先生:マウスポインタの形を変えたいコンポーネントの、「Cursor」プロパティで種類を設定してね。今回は、pbxDrawペイントボックスに設定する。マウスポインタの形は「crCross」で十字型にしよう。

ナッキー:マウスポインタには、いろいろな形があるんですね。


記述できたら、マウスポインタの形を変更します。pbxDrawペイントボックスを選択して、オブジェクトインスペクタ、プロパティページで「表示」カテゴリの「Cursor」プロパティに「crCross」を設定します。

設定できたら、保存して実行してみます。ツールバーの[すべて保存]ボタンをクリックして保存します。次にツールバーの[実行]ボタンで実行テストします。ペイントボックス上でマウスを動かすと、ステータスバーの数値がマウスにあわせて変わります。

Hide image
04ステータスバーへの表示

図04 ステータスバーへの表示

    メニューの作成

ステータスバーはこれで、OKね。次は、メニューを作るって言ってたわよね。メニューコンポーネントなんていうのがあるのかな?教えて、高橋先生!

高橋先生:メニューを作るために、コンポーネントを使うというのは正解。多分ナッキーがイメージしているのとは、違うと思うんだ。きっと、「ファイル(F)」っていうコンポーネントをフォームの上に配置するような感じに、考えているんじゃない?

ナッキー:そんなとこかな。違うって、それ以外にどうやって作るんですか?コンポーネントを使うんですよね。

高橋先生:前回、「非ビジュアルコンポーネント」について紹介したよね。今回のメニューを作るコンポーネントも非ビジュアルコンポーネントなんだ。「Standard」カテゴリの「TMainMenu」コンポーネントを使う。

ナッキー:え?メニューは目に見えるのに非ビジュアルコンポーネントなんですか?

高橋先生:TMainMenuコンポーネントをダブルクリックすると、メニューを設計するための「メニューデザイナ」の画面が表示されるんだ。メニュー作りはこのメニューデザイナでやってね。

ナッキー:ダイアログボックスコンポーネントのように配置するだけ、じゃないんですね。

高橋先生:メニューデザイナでメニュー項目を作っていく。操作自体は簡単。メニューの枠を選択して、Captionプロパティを設定する。その時、その時、Captionの文字列に「アクセラレータ文字」を設定するといいね。

ナッキー:アクセル??

高橋先生:アクセラレータ文字にはアルファベットが入っている。キーボードの[Alt]キーを押すとメニューがアクティブになり、そのアルファベットのキーを押すとクリックしたときと同じ動きをするんだ。以前紹介した「ショートカット」と似ているね。

ナッキー:シートカットって何でしたっけ?

高橋先生:コードエディタでコピーするときは、キーボードの[Ctrl]キーを押しながら[C]キーを押す、ショートカットを紹介したよ。ショートカットは、[Ctrl]キーを押しながら、決まったアルファベットのキーを押す。アクセラレータの場合は、メニューを画面上に表示しないと実行できないのに対して、ショートカットは画面表示にかかわらず実行できるんだ。

ナッキー:あ、そうでしたね。いつも何気なく使っていて、忘れちゃっていました。じゃあ、そのアクセラレータ文字はどうやって設定するんですか?

高橋先生:アクセラレータ文字はCaptionプロパティを持つコンポーネントなら、だいたい設定できる。Captionプロパティに「(&アルファベット)」と入力するだけだ。たとえば「ファイル(&F)」というように記述する。カッコはなくてもアクセラレータ文字になるけれど日本語の画面では、アクセラレータにカッコをつける習慣だから覚えてね。

ナッキー:Captionプロパティを持つコンポーネントっていうと、TButtonコンポーネントでも設定できるんですか?

高橋先生:TButtonにもアクセラレータ文字が設定できる。マウスが使えない場合や、キーボードからの操作が好みのユーザーがいるかもしれないからね。今回はメニューに「アクセラレータ文字」と「ショートカット」を設定してみよう。表にして、整理してみよう。

アクセラレータ文字

ショートカット

操作

[Alt]キー、アクセラレータ文字の順に押す

[Ctrl]キーなどと一緒に押す

有効なとき

画面に表示しているとき有効

いつでも有効


ナッキー:すごく良く使う機能はショートカットがいいんですね。メニューにはショートカットキーは設定できないんですか?

高橋先生:設定できるよ。メニューの「ShortCut」プロパティでキーの種類を選ぶだけでOK。アクセラレータ文字と両方を設定することもできるよ。

ナッキー:いろいろな手段を提供した方が、使いやすいってことなのね。

高橋先生:メニューの中には区切り線が入っているものもあるよね。あの区切り線はCaptionプロパティに半角の「-」(ハイフン)を入力して、作ることができる。もしも間違えて作ったときは、キーボードの[Delete]キーで削除する。移動のときはドラッグしてね。


今回メニューにしたい項目は[ファイル]メニューの中に[開く][名前をつけて保存][区切り線][終了]、[編集]メニューの中に[サイズ変更]、[クリア]、[ヘルプ]メニューの中に[バージョン情報]です。では、作ってみますね。フォームデザイナの画面でTMainMenuコンポーネントを配置します。ツールパレットの「Standard」カテゴリから「TMainMenu」コンポーネントを探して、フォームの適当な位置に配置します。非ビジュアルコンポーネントだから、どこに配置してもいいのよね。

配置したMainMenu1をダブルクリック、もしくはマウスの右ボタンをクリックして表示されるメニューから「メニューデザイナ」を選択します。メニューデザイナを表示したら、画面の左上に破線でできた枠を表示しているのを確認します。これが新規作成するメニューになるんですって。オブジェクトインスペクタ、プロパティページで「ローカライズ対象」の「Caption」プロパティに「ファイル(&F)」と入力します。入力ができると、「ファイル(F)」の右に新しい枠を表示しますので、選択して「編集」メニューを作ります。枠を選択して、プロパティページで「ローカライズ対象」の「Caption」プロパティに「編集(&O)」と入力します。次に、新しくできた右側の枠を選択して「ヘルプ」メニューを作ります。枠を選択して、プロパティページで「ローカライズ対象」の「Caption」プロパティに「ヘルプ(&H)」と入力します。

ここまでできたら各メニューを選択して、中のメニュー項目を作成します。「ファイル(F)」を選択すると、下に新しい枠を表示しますので選択します。まずは「開く」メニューを作ります。プロパティページで「ローカライズ対象」の「Caption」プロパティに「開く(&O)...」と入力します。メニューをクリックして別の画面を表示するように作るとき、後ろに「...」と付けるんですって。さらにショートカットも追加します。プロパティページで「ローカライズ対象」の「ShortCut」プロパティで「Ctrl+O」を選択します。同様にして以下の表のようにメニューを作成します。途中、[名前をつけて保存]メニューと[終了]メニューの間に区切り線を入れておきます。Captionプロパティに半角で「-」(ハイフン)を入力します。

ファイルメニュー(F1)

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

ファイル(&F)


編集メニュー(E1)

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

編集(&E)


ヘルプメニュー(H1)

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

ヘルプ(&H)


ファイル - 開くメニュー(O1)

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

開く(&O)...

ローカライズ対象

ShortCut

Ctrl+O


ファイル - 名前をつけて保存メニュー(S1)

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

名前をつけて保存(&S)...

ローカライズ対象

ShortCut

Ctrl+S

入力

Enabled

False


ファイル - 区切り線(N1)

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

-


ファイル - 終了メニュー(X1)

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

終了(&X)


編集 - サイズ変更メニュー(S2)

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

サイズ変更(&S)...


編集 - クリアメニュー(C1)

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

クリア(&C)


ヘルプ - バージョン情報メニュー(A1)

カテゴリ名

プロパティ名

設定値

ローカライズ対象

Caption

バージョン情報(&A)...


Hide image
05メニューデザイナ新規なし

図05 メニューデザイナ

    終了メニューでメッセージボックスの表示

メニューがついただけで、なんだかいろいろできそうな気がしますね。これだけじゃメニューを選んでも何も動かないので、コードを書いて動くようにします。今回コードを書くのは、[終了]メニューのイベントハンドラだけです。計算機を作ったとき「Close」メソッドでプログラムを終了しましたが、今回も同じかしら?教えて、高橋先生!

高橋先生:今回は、メッセージボックスを使って「終了しますか」と表示しよう。

ナッキー:あ、「ShowMessage」で表示するんですよね。

高橋先生:ShowMessage だと[OK]ボタンしかないから、「終了しない」という選択ができないね。だから「MessageDlg」関数を使おう。MessageDlgは関数なので戻り値がある。どのボタンをクリックしたか、が返ってくるんだ。表示できるボタンも[OK]ボタンのほかに[キャンセル]ボタンや[はい]ボタンなどいろいろ用意してあるから、パラメータにどんなボタンが必要か書き込めばいい。

ナッキー:ShowMessageより少し機能が多いんですね。

高橋先生:パラメータは全部で4つある。1つ目がメッセージボックスに表示するメッセージ。2つ目がメッセージボックスの種類。3つ目がボタンの種類。4つ目がヘルプのID。

2つ目のパラメータである、「メッセージボックスの種類」は全部で5種類ある。今回は「mtConfirmation」を設定する。これは疑問符のアイコンが付いたメッセージボックスだ。ほかの種類を知りたい場合は「TMsgDlgType」をヘルプで参照してみてね。3つ目の「ボタンの種類」は、10種類くらいある。追加したいボタンの名前は「[ ]」(角カッコ)の中に、「,」(カンマ)で区切って記述する。今回は「[mbOK, mbCancel]」で、[OK]ボタンと[キャンセル]ボタンが表示できる。ボタンの数は、最大3種類まで追加できる。ほかのボタンについて調べたい場合は「MessageDlgルーチン」をヘルプで参照してね。どのボタンがクリックされたかは、戻り値にボタンの名称が入っていて知ることができる。つまり、MessageDlg の戻り値が「mbCancel」だったら、[キャンセル]ボタンがクリックされたということ。4つ目のヘルプは持っていないので「0」を入れる。

ナッキー:パラメータがややこしいけど、この組み合わせでメッセージボックスの表現が豊富になるんですね。

高橋先生:そういうこと。ところで、メッセージボックスを表示するのは、どのイベントかわかるかな?

ナッキー:そりゃ、[終了]メニューのOnClickイベントでしょ。

高橋先生:じゃあ、フォームの[×](閉じる)ボタンをクリックしたときは、メッセージが出ないよ。

ナッキー:えー!じゃあ、両方にイベントをつけるとか。

高橋先生:ここは、[終了]メニューの方は普通に「Close」メソッドの呼び出しだけ。そして、終了処理をするための「OnCloseQuery」イベントにメッセージボックスを表示するコードを書くんだ。

ナッキー:へぇ~。あ、でもOnCloseQueryは終了するときのイベントなんですよね。だったら、終了を取りやめることはできないんじゃないですか?

高橋先生:ちゃんと、終了しないようにする手段があるよ。フォームのOnCloseQueryイベントは「CanClose」というパラメータを持っている。これは論理型のパラメータで「True」なら終了できて、「False」なら終了できない。イベントハンドラの中でCanCloseパラメータにFalseを代入すれば終了しないようにできるんだ。

ナッキー:それなら、大丈夫ですね。えっと、終了メニューのOnClickイベントハンドラは普通にCloseメソッドで終了していいのね。そして、フォームのOnCloseQueryイベントハンドラでメッセージボックスを表示するんですね。


先に終了メニューをクリックしたとき、プログラムを終了するようにコードを書きます。画面をフォームデザイナに切り替えます。MainMenu1メインメニューコンポーネントをダブルクリックするなどして「メニューデザイナ」を表示します。「ファイル(F)」をクリックして、メニュー項目を展開します。表示したメニューの中から「終了(X)」を選択します。次にオブジェクトインスペクタ、イベントページで「入力」カテゴリの「OnClick」をダブルクリックして、イベントハンドラを作成します。「Close」メソッドを書けばいいのね。太字部分を追加します。

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

次にメッセージボックスを表示するコードを、OnCloseQueryに記述します。画面をフォームデザイナに切り替えて、構造ペインから「frmMain」を選択します。オブジェクトインスペクタ、イベントページで「表示」カテゴリの「OnCloseQuery」をダブルクリックして、イベントハンドラを作成します。MessageDlg関数を呼び出します。メッセージは「'終了しますか?'」、メッセージボックスの種類は「mtConfirmation」、ボタンの種類は「[mbOK, mbCancel]」にします。戻り値が「mbOK」だったら、CanCloseに「True」を代入します。「mbOK」ではなかったら、CanCloseに「False」を代入します。太字部分を追加します。

unit FormDrawing;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, StdCtrls, XPMan, Buttons, Menus, ExtDlgs, ComCtrls;

type
  TfrmMain = class(TForm)
    sbxDraw: TScrollBox;
    XPManifest1: TXPManifest;
    Panel1: TPanel;
    pbxDraw: TPaintBox;
    sbtnHoso: TSpeedButton;
    sbtnFuto: TSpeedButton;
    shpColor: TShape;
    ColorDialog1: TColorDialog;
    stbMain: TStatusBar;
    MainMenu1: TMainMenu;
    F1: TMenuItem;
    E1: TMenuItem;
    H1: TMenuItem;
    N1: TMenuItem;
    O1: TMenuItem;
    S1: TMenuItem;
    N2: TMenuItem;
    X1: TMenuItem;
    C1: TMenuItem;
    A1: TMenuItem;
    procedure pbxDrawMouseMove(Sender: TObject; Shift: TShiftState; X,
      Y: Integer);
    procedure pbxDrawMouseDown(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure FormCreate(Sender: TObject);
    procedure pbxDrawPaint(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure shpColorMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);
    procedure X1Click(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure pbxDrawMouseLeave(Sender: TObject);
  private
    { Private 宣言 }
    preX: Integer;
    preY: Integer;
    bmpBuf: TBitmap;
  public
    { Public 宣言 }
  end;

var
  frmMain: TfrmMain;

implementation

{$R *.dfm}

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
  begin
    bmpBuf.FreeImage;
    FreeAndNil(bmpBuf);
  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);
  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.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.

記述できたら保存して実行してみましょう。ツールバーの[すべて保存]ボタンをクリックしてから[実行]ボタンをクリックします。メニューバーから「終了(X)」メニューを選択して、メッセージボックスを表示します。[キャンセル]ボタンをクリックして、終了しないことを確認します。次にフォームの[×](閉じる)ボタンをクリックして、メッセージボックスが表示されるかな?やった。うまくいきました。ここでは[OK]ボタンをクリックして通常の終了をするか確認します。

Hide image
06終了メッセージ

図06 終了メッセージ

ナッキー:ちゃんとメニューができましたね。メニューの外観ができたら、すっかり完成した気分になっちゃいました。

高橋先生:まだ、まだ動きが作れていないんだから、完成じゃないよ。

ナッキー:今回はメニューバーとステータスバーができると、本格的なプログラムっぽくなりますね。そっか、まだまた完成じゃないんだ。

高橋先生:やることは山積みなんだから、がんばってやってもらわなくっちゃ。

ナッキー:でもね、今日はこれから歌舞伎座に行くんです。通し狂言なんて久しぶりだわ。仁左衛門様~♪

高橋先生:だから、それどころじゃないって。残りのメニューが、まだたくさんあるんだ。あーまったく、ナッキーって歌舞伎が趣味なの?渋好み?

次回はダイアログボックスを使って、ファイル操作をするメニューを追加するぞ~。


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

Prev | Next | Index


Server Response from: ETNASC01