[リストへもどる]
一括表示

投稿時間:2004/03/11(Thu) 15:28
投稿者名:しょうだい
Eメール:
URL :
タイトル:
タイマー処理中にメニューバーをクリック
タイマーコントロールによるタイマー処理中にメニューバーのメニュー名
(例えば「ファイル」)をクリックしてサブメニューのリストが表示された
状態の時に処理中のタイマー処理が止まってしまいます。
そういうものなのでしょうか?
処理が止まらないような回避方法があるのでしょうか?
何方かご存じの方がおられましたら、ご教授お願い致します。

(具体例)
 ・フォームにラベルとタイマーコントロールを配置。
 ・メニューバーに「ファイル」及びそのサブメニューに「閉じる」を設定。
 ・以下のソースのタイマー処理中にメニューバーの「ファイル」をクリックし、
  サブメニューを表示させた状態の時にタイマー処理が中断してしまう。
  (ラベルコントロールが更新されない。)

Private Sub Form_Load()
    tmrUpdate.Interval = 500
    tmrUpdate.Enabled = True
End Sub

Private Sub tmrUpdate_Timer()
    Dim i As Integer
    Dim j As Integer
    tmrUpdate.Enabled = False
    lblTime.Caption = Format$(Now, "hh:mm:ss")
    For i = 1 To 10
        For j = 1 To 10000
            DoEvents
         Next j
    Next i
    tmrUpdate.Enabled = True
End Sub

(開発環境)
 Visual Basic 6.0 (SP5)
 OS : Windows2000 Professional

投稿時間:2004/03/11(Thu) 16:44
投稿者名:とろ
Eメール:
URL :
タイトル:
Re: タイマー処理中にメニューバーをクリック
私の環境では、止まったり止まらなかったりですね。
Win2k(SP3) + VB6(SP5)

私が考えるに、Timer イベント処理中の
  For j = 1 To 10000
    DoEvents
  Next j
の DoEvents の時にメニューをクリックした場合
DoEvents を呼んでいるので、当処理は一時中断し、
メニューをクリックしたというイベントの方を処理するようになり、
メニューから何かを選択するまでは、
当処理はストップした状態(タイマーが動かない状態)に
なるのではないでしょうか?

逆に、
Timer イベント処理中でない場合にメニューをクリックした場合
タイマーは動いた状態になりますが、
メニューの方の動作がおかしくなってしまいます。

という感じだと思いますが...
# 文章で書くのは難しいですね。

投稿時間:2004/03/11(Thu) 16:51
投稿者名:kamurin
Eメール:kamurin@hotmail.com
URL :
タイトル:
Re: タイマー処理中にメニューバーをクリック
書いてあった処理試してみました。

DoEventsを10000X10回呼んでるのが原因だと思います。
思いますってだけですけど、他に影響なければ、
DoEvents呼ばずにやってみて下さい。

一応私の方では、タイマー止まらなかったので
たまたまかもしれないけど

はっきりしない回答ですみません

投稿時間:2004/03/11(Thu) 19:11
投稿者名:しょうだい
Eメール:
URL :
タイトル:
Re^2: タイマー処理中にメニューバーをクリック
ありがとうございました。

実際は、(具体例)のソースの「For i =1 ・・・ Next i」のところが
別な内容になっているのですが、その処理を途中で中止できるように
したいので、DoEvents を入れています。
(実際のプログラムでは、DoEventsの実行は数回なんですが... )

とろさんのおっしゃるようにメニューのクリックイベントで何らかの
選択待ちになってしまい、タイマーの処理が止まってしまってしまう
のかもしれませんね。
ただ、メニューコントロールの Enabled を False にしてもクリック
には反応して同じ症状になってしまいます。
何とか回避できる方法があればいいのですが...

投稿時間:2004/03/12(Fri) 21:19
投稿者名:ねろ
Eメール:
URL :
タイトル:
Re^3: タイマー処理中にメニューバーをクリック
DoEventsが呼び出されるのが早すぎるような。
For i = 1 To 10
    For j = 1 To 10000
        If j Mod 100 = 0 Then
           DoEvents
        End If
    Next j
Next i

それぞれ環境が違うんで、はっきり断定は出来ませんが。
この例は、こんな事で解決できるかも。
>実際のプログラムでは、DoEventsの実行は数回なんですが
この意味が今ひとつ理解できません。

投稿時間:2004/03/15(Mon) 09:45
投稿者名:しょうだい
Eメール:
URL :
タイトル:
Re^4: タイマー処理中にメニューバーをクリック
アドバイスありがとうございます。

> >実際のプログラムでは、DoEventsの実行は数回なんですが
> この意味が今ひとつ理解できません。

すみません、具体例が適切ではなかったかもしれません。
少々変更させて頂きます。
以下のソースのタイマー処理中(ラベルのカウント表示中)に
メニューバーの「ファイル」をクリックし、サブメニューを
表示させた状態の時にタイマー処理が中断してしまいます。
(ラベルのカウント表示が更新されません。)

(具体例)
 ・フォームにラベルとボタンとタイマーコントロールを配置。
 ・メニューバーに「ファイル」及びそのサブメニューに「閉じる」を設定。

Private m_blnCancel As Boolean

Private Sub cmdCancel_Click()
    m_blnCancel = True
End Sub

Private Sub Form_Load()
    m_blnCancel = False
    tmrUpdate.Interval = 5000
    tmrUpdate.Enabled = True
End Sub

Private Sub tmrUpdate_Timer()
    Dim i As Integer
    Dim j As Integer
    Dim k As Integer
    tmrUpdate.Enabled = False
    m_blnCancel = False
    For i = 1 To 10
        lblTime.Caption = "Count : " & CStr(i)
        DoEvents
        If m_blnCancel = True Then
            Exit For
        End If
        For j = 1 To 10000 
            For k = 1 To 2000: Next k
        Next j
    Next i
    lblTime.Caption = ""
    tmrUpdate.Enabled = True
End Sub

Private Sub Form_Unload(Cancel As Integer)
    End
End Sub

(開発環境)
 Visual Basic 6.0 (SP5)
 OS : Windows2000 Professional (SP4)
  CPU: Celeron 1.70GHz

投稿時間:2004/03/15(Mon) 11:23
投稿者名:ねろ
URL :
タイトル:
Re^5: タイマー処理中にメニューバーをクリック
100%の確信は持てませんが、メニューバーをプルダウンした時に
DoEvensが無くても次の状態を見るために、優先度の高い割り込みがかかっているようです。
その為に、
For j = 1 To 10000 
  For k = 1 To 2000: Next k
Next j
のループを処理するのに、かなりの時間がかかり
その外にあるラベルの表示に処理が回りません。
いずれにしろ、For Nexだけで遅延をするのは少々無理があると思います。
Timerで表示時間を一定にするか、APIのTimeGetTime等の
関数でタイマーを作ることをお勧めします。

投稿時間:2004/03/15(Mon) 16:03
投稿者名:しょうだい
Eメール:
URL :
タイトル:
Re^6: タイマー処理中にメニューバーをクリック
ありがとうございました。

> 100%の確信は持てませんが、メニューバーをプルダウンした時に
> DoEvensが無くても次の状態を見るために、優先度の高い割り込みがかかっているようです。

私もメニューバーのクリックのイベントが影響しているのかと思い、
タイマー処理の最初でメニューを無効(具体例で、mnuFile.Enabled = False)
としても同じでした。
メニューは Enabled = False としてもイベントとはなりませんが、
クリックを認識してしまうようですね。

投稿時間:2004/03/15(Mon) 21:23
投稿者名:ねろ
Eメール:
URL :
タイトル:
Re^7: タイマー処理中にメニューバーをクリック
プログラムを次のように書き換えて見ました
これで何もしなければ、0.5秒に一回ループを回るはず、

Private Declare Function timeGetTime Lib "winmm.dll" () As Long

Private Sub tmrUpdate_Timer()
    Dim i As Integer
    Dim j As Integer
    Dim k As Integer
    Dim t As Long
    Dim n As Long
    tmrUpdate.Enabled = False
    m_blnCancel = False
  
    For i = 1 To 10
        lblTime.Caption = "Count : " & CStr(i)
        DoEvents
        If m_blnCancel = True Then
            Exit For
        End If
        t = timeGetTime
        Do
            DoEvents
        Loop While (timeGetTime - t < 500)
      
        'For j = 1 To 10000
            'For k = 1 To 2000: Next k
        'Next j
  
      Next i

    lblTime.Caption = ""
    tmrUpdate.Enabled = True

End Sub

そして次のことを発見しました。
タイマーが始まる前又はタイマーとタイマーの間にメニューを選択すると、
メニューをプルダウンしてもタイマーはスターとしてループ表示は続行する、
ただしDoeventsを受け付けない。
タイマー処理中にメニューをプルダウンすると、処理が止まる。
これはしょうだいさんのオリジナルのコードでも同じです。
これはいったい何だろう、今夜は寝れなくなりそう。(^^;

投稿時間:2004/03/16(Tue) 16:20
投稿者名:ねろ
URL :
タイトル:
Re:こんなことでは
プログラムの処理中にプルダウンメニューが選択されると、
その時点で割り込みがかかり、メニューのポーリングが
始まる。そしてこのメニューの処理が終了しない限り、元の
処理は再開しない、従ってメニューが出ているうちは
ループカウンターはインクリメントされない。
しかし、既にタイマーが作動してまだタイムアップ
しないうちに、メニューが選択されると、プルダウンメニュー
中にタイマーの割り込みがかかり、タイマー割り込みに書かれた処理を
行う。こんなことではないでしょうか。

投稿時間:2004/03/16(Tue) 19:28
投稿者名:しょうだい
Eメール:
URL :
タイトル:
Re^2:こんなことでは
ねろさん、いろいろとありがとうございます。

私もタイマー処理が停止してしまうのはメニューの選択による
割り込みの影響だとは思います。
ただ、メニューの Enabled を False にしても同様の症状に
なってしまうのですよね。
(クリックイベントは発生しませんが、クリックには反応して
 しまいます。)
やはり、回避しようがないのでしょうね。(;_;)

投稿時間:2004/03/16(Tue) 21:50
投稿者名:ねろ
Eメール:
URL :
タイトル:
Re^3:こんなことでは
VBの場合なぜかメニューバーはEnable=Falseにしても、押す事が
出来てしまうんですよね。Real Timeでプログラムを動かしたい場合は
誰かがちょっとメニューを覗いたりした時処理が止まってしまい、不便ですね。
いっそ止めてほしくない時にはメニューのEnable=Falseにする代わりに
Visible=Falseにしてしまったらいかがですか。

投稿時間:2004/03/17(Wed) 10:27
投稿者名:しょうだい
Eメール:
URL :
タイトル:
Re^4:こんなことでは
> いっそ止めてほしくない時にはメニューのEnable=Falseにする代わりに
> Visible=Falseにしてしまったらいかがですか。
そうですね、見た目はよくないかもしれませんが、対策方法の一つとして
検討してみます。
(ちなみに実際のプログラムでは、タイマー処理で外部からの要求の有無を
 確認しているのですが、ユーザーがメニューをクリックした状態で放置したら
 要求が受け取れないという事態になってしまうことも考えられますので。)
いろいろとありがとうございました。