none
Timer1 control stops while Timer2 does not finishs task

    Question

  • I am using VB 2010. In Form1 I have two Timer controls: Timer1 and Timer2. Timer1 keeps TimeOfDay updated on TextBox1 while Timer2 performs a task every time TimeOfDay reaches some values, which takes 10 seconds ( several beeps for instance). TimeOfDay shown on TextBox1, second after second, stops while task performed on Timer2 is being carried out. Once task finished TimeOfDay restarts running form actual time. I would like to have time running even during task performed.
    Wednesday, July 24, 2013 5:50 PM

Answers

  • Forms Timers are not re-entrant.  You can do a couple of things.  You might call a Delegate where you move the code from Timer2 using BeginInvoke syntax from the Timer2.Tick event.  You might create a worker thread (similar to a Delegate, though different in detail), or you might choose to use a System Timer(s) instead of Forms timers (alternately, use a Thread timer, with similar operation).  If the code in Timer2 interacts with the UI, perhaps the simplest is to call a Delegate.  If you use a Delegate or worker thread to off-load execution from Timer2, you will need to set Timer.Enabled = False until the associated code has completed, so that the re-entrance that you now allow does not mess up.

    Next (depending on what Timer2 code does), you might use something like this simple-minded expedient:

        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            Timer1.Interval = 100
            Timer1.Enabled = True
            Timer2.Interval = 1000  
            Timer2.Enabled = True
        End Sub

        Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
            TextBox1.Text = Now.TimeOfDay.ToString
        End Sub

        Private Sub Timer2_Tick(sender As System.Object, e As System.EventArgs) Handles Timer2.Tick
            Dim Timeout As Double = Now.TimeOfDay.TotalSeconds + 10
            Dim Count As Long
            Do Until Now.TimeOfDay.TotalSeconds > Timeout
                Count += 1
                TextBox2.Text = Count.ToString
                Application.DoEvents()
                System.Threading.Thread.Sleep(0)   'usually, I would choose Sleep(1), but that introduces latency that may not be acceptable
            Loop
        End Sub

    Application.DoEvents() is not a recommended approach, but sometimes simple things work as well as more complex ones.  Of course, if you aren't using some sort of loop in Timer2, revisit the Delegate, worker Thread, or System.Timer approaches.

    Additionally, recognize that both worker threads and threads created by System.Timer cannot interact with the STAThread UI objects directly, but must delegate that interaction.

    Lastly, someone else may have alternate suggestions.  There really is no single answer.

    Dick


    Dick Grier. Author of Visual Basic Programmer's Guide to Serial Communications 4. See www.hardandsoftware.net.

    Wednesday, July 24, 2013 6:50 PM
  • What happens is that the activity of your task takes over the UI thread. What you can do is use a BackgroundWorker, which makes a new thread for you, thus leaving the UI thread (which is the one your "normal" code runs on) to update the display as required. The link gives examples which you can work from; it may take a little bit of head-scratching, but it is worth learning about.

    If the only thing it is doing is beeping, you could look at stackoverflow.com/questions/2751686/how-can-i-execute-a-non-blocking-system-beep (in C#, so translating to VB from that would be another new thing to learn).

    HTH,

    Andrew

    Wednesday, July 24, 2013 6:51 PM

All replies

  • Forms Timers are not re-entrant.  You can do a couple of things.  You might call a Delegate where you move the code from Timer2 using BeginInvoke syntax from the Timer2.Tick event.  You might create a worker thread (similar to a Delegate, though different in detail), or you might choose to use a System Timer(s) instead of Forms timers (alternately, use a Thread timer, with similar operation).  If the code in Timer2 interacts with the UI, perhaps the simplest is to call a Delegate.  If you use a Delegate or worker thread to off-load execution from Timer2, you will need to set Timer.Enabled = False until the associated code has completed, so that the re-entrance that you now allow does not mess up.

    Next (depending on what Timer2 code does), you might use something like this simple-minded expedient:

        Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
            Timer1.Interval = 100
            Timer1.Enabled = True
            Timer2.Interval = 1000  
            Timer2.Enabled = True
        End Sub

        Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
            TextBox1.Text = Now.TimeOfDay.ToString
        End Sub

        Private Sub Timer2_Tick(sender As System.Object, e As System.EventArgs) Handles Timer2.Tick
            Dim Timeout As Double = Now.TimeOfDay.TotalSeconds + 10
            Dim Count As Long
            Do Until Now.TimeOfDay.TotalSeconds > Timeout
                Count += 1
                TextBox2.Text = Count.ToString
                Application.DoEvents()
                System.Threading.Thread.Sleep(0)   'usually, I would choose Sleep(1), but that introduces latency that may not be acceptable
            Loop
        End Sub

    Application.DoEvents() is not a recommended approach, but sometimes simple things work as well as more complex ones.  Of course, if you aren't using some sort of loop in Timer2, revisit the Delegate, worker Thread, or System.Timer approaches.

    Additionally, recognize that both worker threads and threads created by System.Timer cannot interact with the STAThread UI objects directly, but must delegate that interaction.

    Lastly, someone else may have alternate suggestions.  There really is no single answer.

    Dick


    Dick Grier. Author of Visual Basic Programmer's Guide to Serial Communications 4. See www.hardandsoftware.net.

    Wednesday, July 24, 2013 6:50 PM
  • What happens is that the activity of your task takes over the UI thread. What you can do is use a BackgroundWorker, which makes a new thread for you, thus leaving the UI thread (which is the one your "normal" code runs on) to update the display as required. The link gives examples which you can work from; it may take a little bit of head-scratching, but it is worth learning about.

    If the only thing it is doing is beeping, you could look at stackoverflow.com/questions/2751686/how-can-i-execute-a-non-blocking-system-beep (in C#, so translating to VB from that would be another new thing to learn).

    HTH,

    Andrew

    Wednesday, July 24, 2013 6:51 PM
  • Thank you. I will try to implemente your suggestion. I am very beginner in VB.

    Fabio

    Brazil


    • Edited by Fabio Giannoni Friday, July 26, 2013 3:25 PM English correction
    Wednesday, July 24, 2013 9:33 PM
  • Thank you. I will try to implemente your suggestion. I am very beginner in VB.

    Fabio

    Brazil


    • Edited by Fabio Giannoni Friday, July 26, 2013 3:26 PM English correction
    Wednesday, July 24, 2013 9:33 PM