Delphi入門

メニュー設計にまず慣れよう!

レイアウト

では、まず最初にいつも通り、 フォームのレイアウトを作成してみましょう!取りあえずは以下を真似して下さい。

簡易エディタ・レイアウト例

新しいものが出てきましたが、 これらはすべて実行時に表にコンポーネントのこのマークが見える事のない「非ビジュアルコンポーネント」です。 「TMainMenu」は「Standard」タブから、各種ダイアログは「Dialogs」という所にありますのでそれぞれ適当な場所に配置して下さい。 別にこの通りに配置する必要はありません!「非ビジュアルコンポーネント」は配置場所はどこでも構いません。

そして、TMemoを配置します。図ではフォーム全体に拡大しています。 これは「Delphiの凄さを知ろう!」でもこのようになっていたと思いますが、 このTMemo(複数行書けるWindows標準メモ帳ライクなコンポーネント)を配置した後に、 「オブジェクト インスペクタ」の「Align」を「Client」に変えます。

これにより、常に最大化された状態になります。 ウィンドウの大きさを変えても常に最大化を維持できるようにできます。この「Align」は結構使います。 そして「Lines」から最初は「Memo1」と記入されてますのでこれをクリアしちゃって下さい。これでベース終わりです。ここではし忘れましたが、「ScrollBars」という所も設定しておいて下さい。現在では、「ssBoth」でいいと思います。そうすると縦横にスクロールバーが入ったと思います。

「Delphiの凄さを知ろう!」のサンプルで紹介したものは、 このTMemoを配置して、「Align」を「alClient」にして配置して、。それを実行しただけです。 実際に現段階で実行して見て下さい。きちんとメモ帳として動くはずです。 後は、これにセーブなどの機能を付けて行くという作業をコツコツして行けば完成できます。 じっくりと見て行く事にしましょう。

まずは、TMainMenuから説明して行きたいと思います。 このコンポーネントはファイルメニューを作るためのコンポーネントです。 よく「ファイル」「編集」などと行ったメニューバーがありますが、 このようなメニューを簡単に作る事ができます。 このコンポーネントをダブルクリックして下さい。

メインメニューの編集

作り方は簡単です。 Captionの値をどんどん変更して行けば自動的に作成してくれます。 やってみれば分かると思いますのでやって見て下さい。

また、「Caption」を「-」(ハイフン) とすると区切り線となります。ショートカットキーの設定も「ShortCut」という所で設定できますので、 非常に簡単にメニューが作れる事がお分かりになると思います。

「検索」と「ヘルプ」についてはちょっとお待ち下さい。 今はこの2つの話を中心に進めて行きますので検索などの高度なものは一番最後に触れたいと思います。 ここでは飾りとして付けて見て下さい。これはメモ帳をちょっと真似しました。 「編集」の方も次のような感じでサクサク作って見て下さい。

メインメニューの編集2

それで、どこにプログラムを書くのかと言うと、 このメニューの各欄をダブルクリックする事でメニューのその個所が押された時にイベントを起こす事ができるようになります。 まずは、上のが完成したら一度「×」でこのメニュー画面を閉じて下さい。

フォーム上にはメニューが完成していますね。 または、このフォーム上のメニューから「新規」とかを選ぶと自動的に、プログラムが書ける状態になります。 「新規」を選んだ時のイベントを書くときにはこのようにします。

まずは、前回も勉強した、 「開く」という作業をやってみましょう。これは前回の事をきっちり覚えていれば苦労せずに出来るはずです。 また、各メニューの「Name」なんですが、 「開く」とか打つと自動的にDelphiは判別して「Name」を「Open1」とかに変えてくれます。 基本的な日本語を変換してくれるのも素晴らしいと思います。 でも、通常は「N45」などのような名前になっているので嫌ならば「Name」を各メニューの項目すべてを確認して変えましょう!

今は初級の話なのでコンポーネント名(プロパティのNameの値)は設置した時のデフォルトの値を使っていますが、 実際にアプリケーションを作る時には、最初の3文字でコンポーネントが分かるようにすると良いです。 例えば、メニューなら、"mnuOpen"、ラベルなら"lblScore"、一行テキストなら"txtFileName"のように記述して行くと良いでしょう。

Windowsのメモ帳の仕様は!?

ここでいきなり問題が出てきます。 「新規」にせよ、「開く」にせよ、メモ帳ですでに書かれていた場合は「変更されています、 保存しますか?」というのがメモ帳では出てきます。まずはそれに対処しなくてはなりません!

いきなりファイルを読み込んでしまっては、 前にせっかく書いたものを無視してファイルを開くという事もできますが、それはエディタとしては不完全です。 ですから、きちんと「変更されています。保存しますか?」というのを確認させるメッセージを出すような処理をする必要があります。 エディタの内容が変更されているかどうかを確認するには、

Memo1.Modified

を使います(「モディファイド」と読んで下さい)。 これはBoolean型(真偽値 - True/False)ですので、 もしMemo1の内容が変更されていたらTrueを、変更されてなければFalseを返します。

つまり、Memo1に何かキーボードで文字を書き始めた瞬間、 ずっとTrueになるという事です。しかし、一度保存したら、この値をFalseにして上げるという作業がここでは必要です。 一度保存したものは、変更なしに戻す必要がありますよね?そして、また書いたら変更ありに…という事をしてあげます 。結構、色々な事が交錯しているので混乱するかと思いますが、 じっくり考えればさほど難しい事をしている訳ではありません。

名前を付けて保存

それでは、まずは「名前を付けて保存」から見て行きます。 何故、これから始めるかは後でひどくよく分かります(笑)。 「名前をつけて保存」の際にはよく保存場所を指定するダイアログが出てきます。 あれをするのには、「TSaveDialog」が必要です。そのために配置してあります。 使い方は、「TOpenDialog」と殆ど同じです。軽く見て行きましょう。

procedure TForm1.SaveAs1Click(Sender: TObject);
begin
   if SaveDialog1.Execute = True then
   begin
      Memo1.Lines.SaveToFile(SaveDialog1.FileName) ;
   end ;
end;

上記でOKなのは何となくお分かりでしょうか? 「= True」は省略可能です。普通は省略します。「Execute」すると、ファイル保存用ダイアログが起動します。 そして、「SaveDialog1.FileName」には、記入したファイル名(絶対パス)がそこに格納されます。 この数行で、指定したファイルへ書いた内容を保存という作業を行っています。

これをC言語とかですと、 ファイルポインタがうんちゃら…というので非常に初心者に取っては煩わしいものとなるでしょう。 そこがDelphiの強みです。さて、これで「名前を付けて保存」は完成です。 また、フィルタについても設定して下さい。

よく分からない方は、 タイピング制作講座のファイルからデータを読み込むをもう一度じっくりとお読みになって下さい。 更に理解が深まるはずですので。そうでない方ももう一度目を通しておく事をお奨めします。

ファイルを開く

それでは、次に「開く」です。これも根本的に同じですが、 メモ帳などを頻繁に使っている人はお気づきかと思いますが、 メモ帳のタイトルバーの所にはそのファイルのパスが書かれていますね?というので、 開いたらそのパスをタイトルバーに記入させてみます。現在はここでは「簡易エディタ」になってます。

procedure TForm1.Open1Click(Sender: TObject);
begin
   if OpenDialog1.Execute then
   begin
      Memo1.Lines.LoadFromFile(OpenDialog1.FileName) ;
      Form1.Caption := OpenDialog1.FileName ;
   end ;
end;

読み込みも完成しました。 しかし、存在しないファイル名を記述してしまった場合には開けません。 そういうエラーにもきちんと対処してくれているのですが、エラーメッセージを自分で出したい場合は、 「オブジェクト インスペクタ」の「Option」で「ofFileMustExists」という所を「True」にすれば対処してくれるようになります。 その他のはヘルプを御覧になって下さい。

そして、2行目でフォームのCaption、 つまりタイトルバーの所を指定したファイルパス名(絶対パス名)にする作業を行っています。 これで、読み込みは一応完成しました。あくまで一応です。その理由は後で分かります。 取りあえずこれで保留という事にしておいて下さい。

上書き保存

次に、「上書き保存」です。これも非常に簡単だと思います。「上書き保存」というのは、、、

  • メモ帳が新規ファイルならば… → 「名前を付けて保存」を実行
  • メモ帳が既存ファイルならば… → 「上書き保存」を実行
procedure TForm1.Save1Click(Sender: TObject);
begin
   if FileExists(Form1.Caption) then
      Memo1.Lines.SaveToFile(Form1.Caption) else SaveAs1.Click
end;

上記のように一行で書けます。 もし、タイトルバーに書かれたものがファイルとして存在するのであれば… (起動直後は「簡易エディタ」となっているのでこんなファイル名は当然存在しませんので、 判定はFalseとなります。「開く」を実行すればこれが「C:\sample.txt」)などとなります。

そして、もし書いているものがすでに存在するものであれば、 普通に「SaveToFile」命令を… そうでなければ、「SaveAs1.Click」つまり、「名前を付けて保存」をクリックした時のイベントを起こす! という事をしています。

新規作成

そして、「新規」です。 新規ファイルを作成の際には、まずメモ帳が変更されてないか?変更されているのなら保存を… そうでなければフォームのCaptionをまた「簡易エディタ」にして、内容をクリアする… というような作業で行けるのはすぐに分かると思います。

ここで、Form1のCaptionは別に 「新規ファイル」とかでも構いません。上のように「FileExists」で判別しているため、 新規ファイル作成時にForm1のCaptionを「C:\sample.txt」とかしてしまうとマズいですけどね。 そんな事する人いないと思いますのであえて言いません。なので、これも次のように行けます。

procedure TForm1.New1Click(Sender: TObject);
var ans : Word ;
begin
   if Memo1.Modified then
   begin
      //Memo1が変更されているならば…
      ans := MessageDlg('変更されています。保存しますか?',
                             mtConfirmation,[mbYes,mbNo,mbCancel],0) ;
      if ans = mrCancel then Exit ;
      if ans = mrYes then Save1.Click ;
   end else
   begin
      //Memo1が更新されていないならば…
      Memo1.Lines.Clear ;
      Form1.Caption := '簡易エディタ' ;
   end ;
end;

さてさて、難しいのが出て来ました。 しかし、これは現段階ではちょっと説明するのに手間がかかりますので、ソースをコピーして下さい。 次期に慣れてくれば理解できるようになります。実際に実行してみればどのようになっているか分かります。

これはメッセージボックス(showmessage)の強化版で複数選択肢が選べます。 「mbYes」とかは「はい」のボタンを配置するためです。 また、最後の「0」という数値はこのメッセージダイアログが出た時に何番目のボタンにフォーカスを当てるかを示すだけですので大した意味はありません。 「1」にすれば「mbNo」つまり、「いいえ」にフォーカスが当たってます。

そして、このメッセージダイアログ(MessageDLG)関数の戻り値はWord型という特殊な形です。 Word型は一種の整数だと思ってください。 「mbYes」つまり「はい」ボタンが押された場合には変数ansには「mrYes」というものが格納されております。 「mb」→「mr」に変わるので注意して下さい。

そして、キャンセルならこの手続きを無視させます。 「はい」を選んだならば、上書き保存させます。 そして、Memo1をクリアして、Form1.Captionを元に戻している訳です。 ここは非常に理解に苦しむかも知れませんが、ぼんやり程度でいいので理解して下さい。

アプリケーションの終了

最後にアプリケーションの終了 という事になります。

procedure TForm1.Close1Click(Sender: TObject);
var ans : Word ;
begin
   if Memo1.Modified then
   begin
      ans := MessageDlg('変更されています。保存しますか?',
                               mtConfirmation,[mbYes,mbNo,mbCancel],0) ;
      if ans = mrCancel then Exit ;
      if ans = mrYes then Save1.Click ;
  end ;
  Close ;
end;

「新規」の最後の2行をクローズに変えただけです。 しかし、これでは行けません。右上の「×」のクローズボックスを押した時は、Form1のOnCloseイベントが発動します。 今回の場合も「Close」と書くと「Form1」の「OnClose」へイベントが渡されます。

しかし、この「OnClose」には何も書かれてません。 何も書かれてない場合は、普通に終了してしまいます。 ですから、ファイルメニューからきちんと「終了」を選んだ場合は正常にこのプログラムが動いて終了されますが、 クローズボックスで終了させた場合は、即座に保存も何もせずに終了してしまいます。

という訳でここには書かずに、「Form1」の「OnClose」イベントに次のように書きます。

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
var ans : Word ;
begin
   if Memo1.Modified then
   begin
      ans := MessageDlg('変更されています。保存しますか?',
                             mtConfirmation,[mbYes,mbNo,mbCancel],0) ;
      if ans = mrCancel then Action := caNone ;
      if ans = mrYes then Save1.Click ;
   end ;
end;

OnCloseイベントはアプリケーション終了イベントです。 「Exit」命令しても強制的に終了してしまいます。ですから、上のようにします。 Actionという引数を指定する事で(キータイプの時も「Key : Char ;」というのがありました。)、 これを「caNone」とする事で終了しようとしているのを回避する事ができます。

終了の際に中止させるにはこのような手法を取りますので注意して下さい。 詳しくはヘルプで「caNone」などで引いて見て下さい。意味は分からないと思いますが、 何となく読めてくると思います。

以上が「ファイル」の操作でした。 なかなかこちらとしてもうまく説明できずに難しい事を話してしまいましたが、 何となく理解できていれば今の所は全然問題ありません。 もう一度じっくり読み直して見て下さい。できるだけ分かり安く書いたつもりですが、 不十分な点があるかも知れません。次は「エディタは文字列処理が命!」に行ってみます。 「ファイル」に比べたら簡単ですので安心して下さい。