タイマー起動中の処理について

解決


L'Kbreth  2007-01-31 03:03:52  No: 97802

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

現在3つのタイマーがあります。(3つ目は起動していません)
1のタイマーは、データを取得しています。取得方法として終わり文字が来るまでDO文にてぐるぐるまわしています。その中でDOEVENTSを入れています。
2のタイマーは、データを解析しています。(解析は10分感覚です)

×ボタンにてフォームが閉じられた時、解析時間が来ていれば解析処理をして終了、もし解析時間が来ていなければ即終了としたいのですがなかなかうまくいきません。

タイマーが起動直後の時は上手くアンロード処理が働くのですが、タイマーが起動し、しばらくした時にフォームを閉じようとすると処理すらしてくれずDOEVENTSを外すと「応答なし」になってしまいます。

Private Sub MDIForm_QueryUnload(Cancel As Integer, UnloadMode As Integer)    
    Dim L%, C As Object
    On Error Resume Next
    
    'メイン以外のフォームを確実にアンロード
    If Not RunMODE.MAINTE Then
        'メンテナンスモード以外はユーザが閉じる操作をキャンセル
        If UnloadMode = vbFormControlMenu Then
            Cancel = True
            Exit Sub
        End If
    End If
        
    For Each C In Forms
        If C.Name <> "MDIMain" Then
        
            If C.Name = "frmMain" Then
                frmMain_Unload = False
                Unload C
                Do
                    If frmMain_Unload Then
                        Exit Do
                    End If
                Loop
            Else
                Unload C
            End If
        End If
    Next
End Sub

Private Sub MDIForm_Unload(Cancel As Integer)

    Set MDIMain = Nothing
    
End Sub

Private Sub Timer1_Timer()
    Dim kei As Single
    Dim sui As Single
    Dim Ret As Integer
    Static Flag As Boolean
    
    If Unload_Flag Then
        'プログラムを終了中かどうか
        With Timer1
            .Enabled = False
            .Interval = 0
        End With
        
        If Timer2.Enabled = False And Timer3.Enabled = False Then
            Unload Me
        End If
        
        call データ取得処理

        Exit Sub
    End If
end sub

Private Sub Timer2Timer()
    Dim kei As Single
    Dim sui As Single
    Dim Ret As Integer
    Static Flag As Boolean
    
    If Unload_Flag Then
        'プログラムを終了中かどうか
        With Timer2
            .Enabled = False
            .Interval = 0
        End With
        
        If Timer1.Enabled = False And Timer3.Enabled = False Then
            Unload Me
        End If
        
        call データ取得処理

        Exit Sub
    End If
end sub

private sub データ取得処理
 do
    処理
    
   DOEVENTS
 loop
end sub

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
    Dim FUN As Boolean
        
    If Timer1.Enabled Or Timer2.Enabled Or Timer3.Enabled Then
        'どれかのタイマーが起動していれば
        Unload_Flag = True
        
        'Form_Unloadイベントを発生させないために
        Cancel = 1
        Exit Sub
    End If
    
    With frmShuttle
        If .Port1.Opened Then
           FUN = .Port1.Close
        End If
    End With
    
    Cancel = 0
    frmMain_Unload = True
End Sub

Private Sub Form_Unload(Cancel As Integer)
    Debug.Print "frmMAIN_Ture"
    Set frmMain = Nothing
End Sub

長々となりすみませんが  宜しくお願い致します


てふ  2007-01-31 08:39:07  No: 97803

まずはコンパイルの通るサンプルを出してください

あと、関係ないかもしれませんが、フォームを閉じようとしたとき
データ取得処理やら、データ解析処理が走っていて、その中でなにか
フォーム上のコントロールにアクセスしていれば、そのフォームは再度
ロードされてしまいますよ。


通ってみた  2007-01-31 21:32:40  No: 97804

Xボタンで終了させるのをやめて、終了用のコマンドボタンを用意すれば話は簡単そうですが・・・


L'Kbreth  2007-01-31 23:27:56  No: 97805

返信ありがとうございます。

終了ボタンを用意するというのは仕様上できないのでやめておきます。

Public ENDFLAG  AS Boolean
pUBLIC KeisokuF AS Boolean

Private Sub Form_Load()
    Timer1.Interval = 3000
    Timer2.Interval = 1000
    Timer3.Interval = 500
    
    Timer1.Enabled = True
    Timer2.Enabled = True
    Timer3.Enabled = False
End Sub

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)

    ENDFLAG = True
    
    Do
        If KeisokuF = False Then
           
           Timer1.Enabled = False
           Exit Do

        End If
        DoEvents
    Loop

    Unload Me
End Sub

Private Sub Form_Unload(Cancel As Integer)
    Set Form1 = Nothing
End Sub

Private Sub Timer1_Timer()
    Static flag As Boolean
    
    If flag Then Exit Sub
    flag = True
    
    Call keisoku    

    flag = False
End Sub

Private Sub keisoku()
    Dim tim As Integer
    Dim t1 As Date
    Dim t2 As Date
    Dim str As String
    
    If ENDFLAG Then
        Exit Sub
    End If
    
    t1 = Now
    
    KeisokuF = True

    Do       
        str = "i"
        str = str & str
        tim = DateDiff("s", t1, Now)
        
        If tim > 10 or ENDFLAG = True Then
            Exit Do
        End If
        DoEvents
    Loop

    KeisokuF = False
End Sub

以上がソースです

Timerからkeisokuを呼び出しその中で10秒間待っているだけなのですが
keisoku処理の途中で×ボタンでフォームが閉じられた場合そのDO文の中でPGが停止されてしまうのですがどのように対処すればいいのでしょうか?


あんび  2007-01-31 23:35:27  No: 97806

タイマー2でもデータを取得に行ってるんですね。
タイマー1の  call データ取得処理  は確実に終了しているのですか?
>DOEVENTSを外すと「応答なし」になってしまいます
を見る限り、データ取得処理が終わってないんでしょう
private sub データ取得処理のループ内のDoEventの後ろにでも
If Unload_Flag Then EXIT DO
を入れて試してみては?


てふ  2007-02-01 09:58:51  No: 97807

なんだかソースを見る限り基礎的なことをいまいち理解してないようなので
簡単なサンプルを書いておきます。
あなたの提示したソースは、ここをこうすればというレベルのソースになって
いませんので。

以下はフォームにタイマー1個貼り付けて、タイマー内の処理が実行された
場合、タイマー内の処理が終了するまでプログラムを終了しないという
サンプルです。

Private Sub Form_Load()
  Timer1.Interval = 10000
  Timer1.Enabled = True
End Sub

Private Sub Timer1_Timer()
  Dim t As Date
  Static bsy As Boolean
  
  If bsy Then Exit Sub
  bsy = True
  t = Now
  Do While DateDiff("s", t, Now) < 10
    Debug.Print Now
    DoEvents
  Loop  
  bsy = False
End Sub


我龍院  2007-02-01 18:38:03  No: 97808

Do Loopに頼りすぎです。
Public flgRequestEnd  As Boolean
Public flgKaiseki As Boolean
Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
    If flgKaiseki Then
        flgRequestEnd = True
        Me.Caption = "終了予約中"
        Cancel = 1
    End If
End Sub
Private Sub keisoku()
    Dim timeStart As Date
    timeStart = Now
    flgKaiseki = True
    Me.Caption = "計測中"
    Do
        If DateDiff("s", timeStart, Now) > 10 Then
            Exit Do
        End If
        DoEvents
    Loop
    Me.Caption = "計測準備中"
    flgKaiseki = False
    If flgRequestEnd Then
        Unload Me
    End If
End Sub

Private Sub Form_Load()と
Private Sub Timer1_Timer()は
そのままで良いので省略してます。
ちょっとこれでやってみてください。


L'Kbreth  2007-02-01 18:53:27  No: 97809

すみません  いろいろと試していて返信できませんでした。(_ _

最終的に
終了ボタンを押された時、終了チェックタイマーを動かしその中で
全ての処理が終わるまで永遠とタイマーを動かし、終了処理をすると
うまくいきましたのでそれを採用しました。

以下は変更前のPGの話です。

計測タイマーが起動すると、3秒周期でデータを採取しにいきます。
データ採取中はDO〜LOOPでまわし中にDOEVENTS
をかましていました。

そしてそのDO〜LOOP中に、閉じるボタンを押されるとクエリーアンロードイベントが発生し、その中で終了フラグが立つまで、その中でもDO〜LOOPでまわしています。そのLOOP内でもDOEVENTSはかましています。(この時計測タイマーは動いています)

しかし、流れは計測タイマー終了後→クエリーアンロードとなってほしいのですが、DOEVENTSによりクエリーアンロードイベントのDO〜LOOP内を永遠と繰り返すだけでした。

以前のソースです

Option Explicit
Private ENDFLAG As Boolean
Private SampFlag As Boolean
Private KEISOKU_TIME As Date

Private Sub Form_Load()
    
    KEISOKU_TIME = Format(DateAdd("d", 1, Now), "yyyy/mm/dd 00:00:00")
    
    Timer1.Interval = 3000
    Timer1.Enabled = True
    
    Timer2.Enabled = True
    Timer2.Interval = 300
End Sub

Private Sub Form_QueryUnload(Cancel As Integer, UnloadMode As Integer)
    ENDFLAG = True
    
    Do
        If SampFlag = False Then
            Exit Do
        End If
        
        DoEvents
    Loop
    
    Debug.Print "おしまい"
End Sub

Private Sub Timer1_Timer()
    Static flag As Boolean
    
    If ENDFLAG Then
        Timer1.Enabled = False
        Timer1.Interval = 0
        
        If Timer2.Enabled = False Then
            Unload Me
        End If
        Exit Sub
    End If
    
    If flag Then Exit Sub
    flag = True
    
        
        SampFlag = True
            Call keisoku
        SampFlag = False
    
    flag = False
End Sub

Private Sub Timer2_Timer()
    Static flag As Boolean
    
    If ENDFLAG Then
        Timer2.Enabled = False
        Timer2.Interval = 0
        
        If Timer1.Enabled = False Then
            Unload Me
        End If
        Exit Sub
    End If
    
    If flag Then Exit Sub
    flag = True
        If KEISOKU_TIME <= Now Then
            '日替わり処理
        End If
    flag = False
End Sub

Private Sub keisoku()
    Dim t1 As Date
    Dim i As Integer
    
    t1 = Now
    i = 0
    Do
        i = i + 1
        Debug.Print i
        
        If DateDiff("s", t1, Now) > 20 Then
            Debug.Print "タイムアウト"
        End If
        DoEvents
    Loop
End Sub

このソース実行すると、タイマーが起動していない、またはタイマー起動直後であれば終了処理が働きますが、CALL KEISOKU中に終了ボタンを押すと固まります。

この謎が知りたかったのですが、ようやく分かりました。
長文になりすみません。

数日間ご指摘ありがとうございました。(^^


L'Kbreth  2007-02-01 20:21:48  No: 97810

我龍院さん  本当にありがとうございます。

今までDO〜LOOPばかり使用していたので、違った手法を教えていただきありがとうございました。

これからいろいろお世話になると思いますが宜しくお願い致します。


※返信する前に利用規約をご確認ください。

※Google reCAPTCHA認証からCloudflare Turnstile認証へ変更しました。






  このエントリーをはてなブックマークに追加