Delphi入門

時間を使って臨場感を出して見よう!

「TTimer」の使い方に慣れよう!

さて、いよいよ時間を扱う事になりました。 これを修得し終わった地点で大幅な改造が出来るようになります。 時間を扱う…というには、例えば、一定時間事に何かのイベントを起こしたり、何か間をおきたいという時です。

「コンポーネントパレット」の「System」から時計のアイコンのコンポーネントを どこか適当に配置して下さい。これも、プログラムを書くだけの非ビジュアルコンポーネントです。「TTimer」といいます。 ここでは、ボタンを押すとパネルが1秒おきに赤→青と切り替わるプログラムを考えて見ます。 また、もう一度ボタンを押すと、止まるというプログラムを考えて見ましょう。

今までの知識ではちょっと難しいですね(^^;)。 色が変わるのは前にやった通りです。問題はこの一定時間というのをどう扱うかです。 この「TTimer」コンポーネントは、一定時間に何かイベントを起こす時に使います。 「オブジェクト インスペクタ」を見て下さい。「Interval」というのがありますね? 「Interval」というのは「間隔」という意味です。ここに数値が設定されていますが、「1000」となってます。 ミリ秒単位で設定するので、この場合は「1秒」おきに処理させるという事になります。 また、「Enabled」というのがあります。これは「使用可能」にするか、「使用不可能」にするか?を決めるものでした。 例えば、まだ試してないと思いますが、「TButton」の「Enabled」を「False」にして実行して見て下さい。 プログラムはかかなくてもOKです。次のようになったでしょうか。

Form1のButton1

このように、ボタンが無効になります。 これが「Enabled」の効果です。勿論、プログラム内で無効にしたい時には、

Button1.Enabled := False ;

と書けばいいのです。これは今までの応用です。ではでは、これを「Timer」コンポーネント、 「TTimer」での「Enabled」はどういう意味かと言いますと、 やっぱり無効にしたり、有効にしたり…という意味です。

Timer1.Enabled
True
「Interval」で指定した時間おき(単位はミリ秒)に、イベント(書かれているプログラム)を実行します。
False
何もイベントを起こしません。
TTimerのイベント

このようになってます。「TTimer」はイベントをひとつしか持ちません。 ですから、コンポーネントをそのままダブルクリックしても必然的にこの「OnTimer」になるわけです。 「OnTimer」ってどういう意味?「タイマーの上」???ではないんです。 ここに書かれているプログラムを一定時間置きに起こすだけです。 と言うよりなんだかんだ言うよりもサンプルプログラムを見て頂ければ分かると思います。

procedure TForm1.Timer1Timer(Sender: TObject);
begin
   Button1.Width := Button1.Width + 1 ;
end ;

「Button1」を配置して見て、 「Timer1」には上のようなプログラムを書いて見て下さい。「Timer1」の「Interval」は「1000」に、 「Enabled」は「True」にして実行して見て下さい。 実行すると、ボタンの幅が1秒おきに横にちょっとづつ広がっているのが分かっていると思います。 ちょっと気持ち悪いですね。でも、こういうのが「Timer」コンポーネントです。

また、「Interval」を今度は「300」くらいにしてやってみて下さい。 周期が速くなったと思います。こういう使い方をします。 次に「Enabled」を「False」にして、実行して見て下さい。違いが分かりましたでしょうか? ではでは、早速これをふまえて遊んで見ましょう!

  1. 「Start」ボタンが押されたら、ボタンのCaptionを「Stop」にして、パネルの色を変える
  2. 次にボタンを押したら「Stop」→「Start」に戻して色が変わるのを止める

という仕組みで行きたいと思います。次の記事で話を進めて行く事にします。

サンプルプログラミング

設置の例を致しましては、以下のような感じに してみました。気に入らない方は全然変えて下さって構いません。

TTimerを使ったアプリケーション
Panel1 : TPanel
Caption := '' ;
Timer1 : TTimer
Enabled := False ;
Interval := 500 ;
Button1 : TButton
Caption := 'Start' ;

それで、初期プロパティ(←「オブジェクト インスペクタ」の各情報の事をこう言います。) は次のようにします。慣れて来るとこういうのは自然と出来るようになりますので、今は真似から初めて下さい。 何でも最初は真似から始まります。と言っても、ある程度知識付いてきてソフトも人の真似ばっかりするのはあまり良くないですが(^^;)。

これで書くプログラムは分かりますでしょうか?ボタンを押したら、「Caption」を「Stop」にして、 「Timer1」の「Enabled」を「True」にして一定時間ごとに処理を起こします。 そして、「Stop」の時に押したらボタンを「Start」に戻して、「Timer1」の「Enabled」を「False」にします。 これは一見簡単そうですが、以外に最初はミスります。よくミスる例は次の通りです。

//ミスし易いプログラム
procedure TForm1.Button1Click(Sender: TObject);
begin
   if Button1.Caption = 'Start' then
  begin
    Button1.Caption := 'Stop' ;
    Timer1.Enabled := True ;
  end ;
  if Button1.Caption = 'Stop' then
  begin
    Button1.Caption := 'Start' ;
    Timer1.Enabled := False ;
  end ;
end;

どこが間違っているか分かりますでしょうか? 前回も実は少しだけ言ったのですが、この場合ですと、プログラムは上から順番に実行して行くので、 これですと「Button1」の「Caption」が「Start」の時に押すと、「Stop」に変わります。 しかし、次の「if」の判定文でまた「Start」に変わってしまいます。 というので永遠に「Start」のままとなってしまうわけです。というので次のように直します。

//正しいプログラム
procedure TForm1.Button1Click(Sender: TObject);
begin
   if Button1.Caption = 'Start' then
  begin
    Button1.Caption := 'Stop' ;
    Timer1.Enabled := True ;
  end else
  begin
    Button1.Caption := 'Start' ;
    Timer1.Enabled := False ;
  end ;
end;

というようにすれば、大丈夫です。これならば、判定文を2つ判定してしまうという事はありませんので安心な訳です。 さて、これは結構出てくるので暗記必須の構文のひとつです。 切り替えの時にはこの「else」を使います。そして、「Timer」には、

procedure TForm1.Timer1Timer(Sender: TObject);
begin
   if Panel1.Color = clBlue then Panel1.Color := clRed
      else Panel1.Color := clBlue ;
end ;

これで、「500ms(=0.5秒)」おきに、このプログラムが実行され、色が変わる訳です。 これをボタンを押すことによって「Enabled」で動くか止めるかを制御します。 これで、実行して見て下さい。うまく動いたでしょうか。これが「Timer」コンポーネント、「TTimer」の使い方です。 これをふまえて、タイピングの問題集を出題し終わってから、何秒かして次の問題へ…という操作へ一歩近づいたようになります。

では、実際に作って見ましょう! まず、何をすれば良いか考えてみます。先程のプログラムをなるべく変更する事なく扱いたい訳ですが、

まず、テキストファイルを読み込んでそこからタイピングし、 問題の出題間隔を単語を打ち終わったらすぐにではなく、単語を打って終わったら1秒間のブランクを置いて、 次の問題へ出題するという方式を採ることにします。 ですから、「Timer」を設置して、「Interval」を「1000」、「Enabled」は「False」にしておきます。前回は、

レイアウト例

というものがありました。これに、「TTimer」を適当に配置して下さい。 基本操作は同じです。時間が入るとプログラムを書く箇所を考えなくてはなりません。 ここからは複雑なのでよく見ておいて下さい。慣れるまでは結構シビアなので頑張って下さい。

//Button1のOnClickイベントに書くプログラム
procedure TForm1.Button1Click(Sender: TObject);
begin
   if Memo1.Lines.Count <> 0 then
      Label2.Caption := Memo1.Lines[0] else showmessage('データがありません!') ;
end ;

//Button2のOnClickイベントに書くプログラム
procedure TForm1.Button2.Click(Sender: TObject; var Key: Char);
begin
   if OpenDialog1.Execute then
   begin
      Memo1.Lines.LoadFromFile(OpenDialog1.FileName) ;
   end ;
end ;

//Form1のOnKeyPressイベント
procedure TForm1.FormKeyPress(Sender: TObject; var Key: Char);
var s : string ;
begin
   s := Label2.Caption ;
   
   if Key = Copy(s, 1, 1) then
   begin
      Delete(s, 1, 1) ;
      Label2.Caption := s ;
   end ;
   
   if Label2.Caption = '' then
   begin
      if Memo1.Lines.Count = 1 then
      begin
         ShowMessage('タイピング完了!') ;
      end else
      begin
         Memo1.Lines.Delete(0) ;
         Label2.Caption := Memo1.Lines[0] ;
         Timer1.Enabled := True ; //Timer1のプログラムを発動させる!
      end ;
   end ;
end ;

//Timer1のOnTimerイベントに書くプログラム
procedure TForm1.Timer1Timer(Sender: TObject);
begin
   Memo1.Lines.Delete(0) ;
   Label2.Caption := Memo1.Lines[0] ;
   Timer1.Enabled := False ; {←超重要!}
end ;

とすればいけますが、お分かりでしょうか?即ち言い換えると、、、

  1. 「Load」ボタンをクリックすると、問題ファイル(テキストファイル)を読み込んでMemo1に読み込む!
  2. 「Start」ボタンでデータが存在すれば、1行目の単語を出題させる!
  3. そして、最終問題でなければTimer1のイベントを起こす!一秒後にTimer1のプログラムが発動します!
  4. つまり、打ち終わった単語の行を消し、次の問題をセットします。そしてTimer1を無効にします!
  5. そしてこれの繰り返しで(3)へ… という風になります。

このような作業を行っております。 ここで、注意して頂きたいのが、4番目です。 ここで、赤字で書かれているように、

Timer1.Enabled := False ;
をしておかなくては行けません。

これをしないと、1秒ごとに「Timer1」はプログラム処理を発動してしまいます。 ですから、ここで、この一行を抜かしてしまうと、どういう事になるかと言いますと… ちょっと考えてみると分かるのですが、

  • 単語を一秒以内で打たないと、また同じ問題が出題されてしまう!

1秒置きにタイマーが発動するのでこうなりますね。ひどくこれはこれで笑えるのですが、 一度試して見て下さい。単語を一秒以内で打つというシビアさに楽しさを覚えるような人はやってみてもおもしろいでしょう(笑)。 ある意味それはそれでおもしろいものができあがるかも知れません。 でも、取りあえず動作を確認してみて違いを区別をする事は何度も言うように非常に重要です。 聞き流すだけではなく実際にやってみて下さい。 「Timer」は「Enabled」が「True」の間は永遠にその動作を規定時間置きに繰り返します。

また、余談ですが「TTimer」では「Interval」に「0」などの値を設定できますが、 判定できる最低値は「55」と言われております。つまり55ミリセカンドより短い間隔は正常に計測できません。 通常は「1000」とかの値の場合にこれを扱います。 ゲーム用などではこれではダメなので、1ミリセカンドまでほぼ正確に計れるコンポーネントもあるのですが、 それはまた自分で探してみてください。私もよく知らないのですが、 リンク先にある「Delphian World」においてあったような気もします。 または、「DelphiX」という「DirectX」をカプセル化したものがあると思います。