DOBON.NET DOBON.NETプログラミング掲示板過去ログ

Timerイベント処理について

分類:[.NET]

2003/09/12(Fri) 13:46:25 編集(投稿者)
2003/09/12(Fri) 13:46:19 編集(投稿者)

いつもお世話になっております。

 コーディングをしているうちにまた問題にぶち当たってしまい、何とか自分で解決
しようと試みたのですが結局解決できず、再度質問させてください。

 現在は、Timerを使用して1秒間(Interval=1000)の周期であるファイルの中にある
値を参照し、前回に参照した時と別の値だった場合はフォーム上のコマンドボタンを
活性(Enabled=True)/非活性(Enabled=False)にするようなコードにしてます。
TimerのEnabledは常にTrueです。

コード例:
Private Sub Timer1_tick(ByVal eventSender As System.Object, ByVal eventArgs As System.EventArgs) Handles Timer1.Tick
  Dim file_path As String   '開きたいファイルのパス
  Dim fnum As Integer     'ファイル番号
  Dim file_status As String  '開いたファイル内にある取得した値
  Dim before_status As String '前回取得した時の値

  file_path = "C:\temp\temp.txt"
  System.Windows.Forms.Application.DoEvents()
  On Error Resume Next

  If FileLen(file_path) = 0 Then 'ファイルが存在しない場合
    Exit Sub          '終了
  Else
    'ファイルを開き、値を取得
    fnum = FreeFile()
    FileOpen(fnum, file_path, OpenMode.Input, OpenAccess.Read)
    file_status = LineInput(fnum)
    FileClose(fnum)

    '前回と同じ値ならリトライ
    If before_status = file_status Then
      Exit Sub
    End If

    '前回取得した値を更新
    before_status = file_status

    '取得した値が"2"の場合はコマンドボタンを活性させる
    If file_status = "2" Then
      Command1.Enabled = True
    Else
      Command1.Enabled = False
    End If
  End If
End Sub


 上記のコードを作成し、実行するとCommand1.Enabled = Trueの処理を行っているにも
かかわらずCommand1は非活性だったりします。デバッグモードで1ステップずつ確認し、
ウォッチ画面でCommand1.Enabledを設定して確認もし、Trueと表示をされているのに
非活性のままなのです。

 しかし、これが毎回そういう現象になるのではなく、何かのきっかけがあるのでは
ないかと思うのですがそれを見つけることができません。他にもTimer2を作成し、
Timer2のIntervalも1000にしてタイマー処理を行っているのもあるのですが、Timer2は
Command1に対しては何も処理は行っておりません。Timer同士のIntervalが同じだと
何かの影響が出てくるとかそういう話なのでしょうか?

 実際にそのコード行を処理して、ウォッチ画面でTrueになっているのも確認でき、
その後開始ボタンを押して全処理を実行させた後もTrueのままだということを確認できる
のにフォーム上では反映されないという現象は起こるのでしょうか?


環境
OS:Win2000 Pro SP4
VS:VS.NET 2003
こんにちは、tinaです。
DoEventが悪いような気がするのですが、

TextBox1(MultiLine=True)を追加し

intSeq += 1
TextBox1.AppendText(intSeq.ToString & vbCrLf)
System.Windows.Forms.Application.DoEvents()
TextBox1.AppendText(vbTab & intSeq.ToString & vbCrLf)
のようにDoEventsをはさんで、
ステップ実行してみてください。
TextBox1.textの結果が
1
  1
2
  2
のように交互にならなくなります。
なので、イベント処理中にイベントを処理しないように
Timer1.Enabled を制御してやるほうがよいのではないかと
追伸
System.Windows.Forms.Application.DoEvents()
にブレイクポイントを置くと再現します。
■No647に返信(tinaさんの記事)

> なので、イベント処理中にイベントを処理しないように
> Timer1.Enabled を制御してやるほうがよいのではないかと

tinaさん、どうもありがとうございます。

 tinaさんがおっしゃられたようにTextBoxを作成し、コードを追加して
試してみたところ、ご指摘通りの動きをしました。私自身DoEvents()関数を
よく理解していなかったのですが、tinaさんがおっしゃるようにDoEvents()
関数が悪さをしているような感じがいたしました。

 しかし、tinaさんが最後にご教授してくださったTimer.Enabledを制御する
方法は仕様上無理なのです。ファイルに書き込まれる値というのは別のアプリ
ケーションで設定されるため、いついかなる時に変更されるのかわからないので
Timerを使用して1秒周期で監視しているのです。
ここらへんの仕様を質問する時に説明せず申し訳ございませんでした。

 DoEvents()関数は最初に発行するのではなくて、Command1.Enabledの後に
記述をすればきちんと再描画されるのでしょうか?
はるかさん、こんにちわ。
YKです。

Timerイベントで表示がおかしいとのことですが、
ツールボックスの「Windowsフォーム」配下のTimerではなく
「コンポーネント」配下にあるTimerを使用してみてもだめでしょうか?

どうやら、「コンポーネント」配下のTimerはマルチスレッド対応型らしく
複数の処理を同時に処理してくれる有能版?になっているみたいです。

DoEventsは、その時点でアプリケーションにたまっちゃってる
イベントをいっせいに吐き出して処理するおまじないで、
はるかさんのおっしゃる現象は、同じインターバルでマルチスレッド型ではない
複数のタイマーを動作させることで、Timerイベントがたまっちゃって
発生するものではないかと思われます。

なのでマルチスレッド対応版のTimerを利用すれば
もしかしたら解決するのかなぁと思っております。

いかがでしょうか?f^^;;
間違っていたらごめんなさい。
すいません、上記、変な名前で投稿しちゃいました。
ごめんなさい〜(汗)
■No652に返信(KOMAさんの記事)

YKさん、ご指摘ありがとうございます。


> どうやら、「コンポーネント」配下のTimerはマルチスレッド対応型らしく
> 複数の処理を同時に処理してくれる有能版?になっているみたいです。

 コンポーネント配下にもTimerが存在していたなんて知りませんでした。
しかもマルチスレッド対応だなんて…。


> DoEventsは、その時点でアプリケーションにたまっちゃってる
> イベントをいっせいに吐き出して処理するおまじないで、

DoEvents()関数とはそのような処理をしてくれるのですか。ヘルプを見てみた
のですが、読解力がないのか知識がないのか理解に苦しむ部分があったのですが
YKさんの説明で漸くちゃんと理解できました。どうもありがとうございます。


> はるかさんのおっしゃる現象は、同じインターバルでマルチスレッド型ではない
> 複数のタイマーを動作させることで、Timerイベントがたまっちゃって
> 発生するものではないかと思われます。

 YKさんのご指摘を受けて、Timer1とTimer2をコンポーネント配下にある
Timerを使用してみたのですがまだ思ったようには動作してくれません。
しかし、不具合発生率は下がったように思われますので、Timerはコンポーネント
配下のを使用していこうと思います。

DOBON.NET | プログラミング道 | プログラミング掲示板