locked
Is it possible to pass a variable to a Timer_Tick event?

    Question

  • I have a short routine in a Timer event that moves a control around the screen. There are two basic variable; The starting location and the ending location. Every tick event changes the .Location property until the end location is reached giving the appearance of the control (lablel) moving.

    I would like to use the Timer event for different start and end locations but the only way I know of is to use Class variables.

    I was hoping that variables could be passed to a Timer_Tick event as other subs.

    Regards Ron

    Saturday, February 11, 2012 3:24 AM

Answers

  • Yes. I believe the answer is there is no way to add your own arguments to the Timer.Tick event handler signature. However I don't think you need to do that. Using class variables as I did in my code should work. As I said earlier, if you have more than one control that you are moving, you can store the information about the movement of that control in the control's Tag property.
    Saturday, February 11, 2012 11:20 AM
  • Use the Tag property:

    Public Class Form1
      Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
        Me.Size = New Size(500, 500)
        Timer1.Interval = 10
      End Sub
      Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles Timer1.Tick
        Dim Pts() As Point = DirectCast(Timer1.Tag, Point())
        Dim ELoc As Point = Pts(1)
        Dim dX, dY As Double
        Static SLoc As Point = Pts(0)
        Static inc As Integer = 100
        dX = (ELoc.X - SLoc.X) / inc
        dY = (ELoc.Y - SLoc.Y) / inc
        SLoc.Y += CInt(dY)
        SLoc.X += CInt(dX)
        inc -= 1
        Label2.Text = SLoc.ToString
        Label1.Location = SLoc
        If inc = 0 Then Timer1.Stop()
      End Sub
      Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Timer1.Tag = New Point() {Label1.Location, New Point(400, 400)}
        Timer1.Start()
      End Sub
    End Class

    Saturday, February 11, 2012 7:18 PM
  • IMO, I suggest you to use System.Timers.Timer class instead of the System.Windows.Forms.Timer class. Because it is much accurate ahd has more precision unit that is less than micro-second.  The alternative is to use StopWatch class which is the most accurate method to measure the time spent in programm codes.

    Just my two cents.


    My blog: http://soho-hsh.blogspot.com

    Sunday, February 12, 2012 12:27 AM

All replies

  • I'm not sure I fully understand what you want. If it is one control that you are moving, but from time to time it has different start and end locations, you should be able to use a class level variable to keep track of it.

    If you have several controls that you are moving around, you could store the start and end locations in the control's Tag property.

    Saturday, February 11, 2012 3:30 AM
  • Hi Blackwood,

    Yes I am using Class level variables at the moment but I was wondering in the variable values could be passed another way.

    A sample of the code is as follows:

    To run it you need 2 Labels, 1 Button and 1 Timer

    Regards Ron

    Public Class Form1
        Dim StartLoc As Point
        Dim EndLoc As Point
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Me.Size = New Size(500, 500)
            Timer1.Interval = 10
        End Sub
        Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
            Dim ELoc As Point
            ELoc = EndLoc
            Dim dX, dY As Single
            Static SLoc As Point = StartLoc
            Static inc As Integer = 100
            dX = (ELoc.X - SLoc.X) / inc
            dY = (ELoc.Y - SLoc.Y) / inc
            SLoc.Y += dY
            SLoc.X += dX
            inc -= 1
            Label2.Text = SLoc.ToString
            Label1.Location = SLoc
            If inc = 0 Then Timer1.Stop()
        End Sub
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            StartLoc = Label1.Location
            EndLoc = New Point(400, 400)
            Timer1.Start()
        End Sub
    End Class

    Saturday, February 11, 2012 3:55 AM
  • As you only have one label to move, I don't think you need the static variables in the Timet.Tick handler and you don't need to be able to pass values to the handler excpet by storing them in class variables. Does this do what you want?

    Public Class Form1
        Private numSteps, moveX, moveY As Integer, StartLoc As Point
    
        Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
            StartLoc = Label1.Location
            moveX = 400 - StartLoc.X
            moveY = 400 - StartLoc.Y
            Timer1.Interval = 10
            Timer1.Start()
        End Sub
    
        Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
            numSteps += 1
            Label1.Location = New Point(StartLoc.X + numSteps * moveX \ 100, StartLoc.Y + numSteps * moveY \ 100)
            If numSteps = 100 Then Timer1.Stop()
        End Sub
    End Class
    

    Saturday, February 11, 2012 4:36 AM
  • Hi Blackwood,

    The short answer is yes it does do what I want but the movement is a lot 'jerkyer' than my code.

    To get a smoother movement I decrement the difference between each point as the current location approaches the end location.

    The further apart the start and end is the greater the number of increments.

    If I understand your code, the increments between each location is constant, i.e. 100 increments, which I believe does not give the smoothest movement and which I tried with past code. Even varying the number of increments (50 - 400) does not improve the smoothness.

    Thanks for your suggestion, if nothing else it gives me some ideas.

    But my question has not yet been answered so I presume that the only way to pass variables to a Timer.Tick handler is by Class variables?

    Regards Ron

    Saturday, February 11, 2012 5:34 AM
  • Yes. I believe the answer is there is no way to add your own arguments to the Timer.Tick event handler signature. However I don't think you need to do that. Using class variables as I did in my code should work. As I said earlier, if you have more than one control that you are moving, you can store the information about the movement of that control in the control's Tag property.
    Saturday, February 11, 2012 11:20 AM
  • Well, except for using class level variables, you could also use Module level variables which they are all built-in public and shared variables.  Surely they can be access throughout your project smoothly.  Such as this:

    Public Module MyModule
      Dim StartLoc As Point
      Dim EndLoc As Point
    End Module
    Public Class Form1
       Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Me.Size = New Size(500, 500)
            Timer1.Interval = 10
        End Sub
        Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
            Dim ELoc As Point
            ELoc = MyModule.EndLoc
            Dim dX, dY As Single
            Static SLoc As Point = MyModule.StartLoc
            Static inc As Integer = 100
            dX = (ELoc.X - SLoc.X) / inc
            dY = (ELoc.Y - SLoc.Y) / inc
            SLoc.Y += dY
            SLoc.X += dX
            inc -= 1
            Label2.Text = SLoc.ToString
            Label1.Location = SLoc
            If inc = 0 Then Timer1.Stop()
        End Sub
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            MyModule.StartLoc = Label1.Location
            MyModule.EndLoc = New Point(400, 400)
            Timer1.Start()
        End Sub
    End Class

    i.e. The Module acts as just like a public class with public static fields and also public static methods.  So the aforementiond Module Usage could also be writeen as a public Class as follows:

    Public Class MyModule
      'Shared keyword in VB.Net means static class member. Just like the static keyword in C#.
      Public Shared StartLoc As Point
      Public Shared EndLoc As Point
      
    End Class
    Public Class Form1
       Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            Me.Size = New Size(500, 500)
            Timer1.Interval = 10
        End Sub
        Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
            Dim ELoc As Point
            ELoc = MyModule.EndLoc
            Dim dX, dY As Single
            Static SLoc As Point = MyModule.StartLoc
            Static inc As Integer = 100
            dX = (ELoc.X - SLoc.X) / inc
            dY = (ELoc.Y - SLoc.Y) / inc
            SLoc.Y += dY
            SLoc.X += dX
            inc -= 1
            Label2.Text = SLoc.ToString
            Label1.Location = SLoc
            If inc = 0 Then Timer1.Stop()
        End Sub
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            MyModule.StartLoc = Label1.Location
            MyModule.EndLoc = New Point(400, 400)
            Timer1.Start()
        End Sub
    End Class



    My blog: http://soho-hsh.blogspot.com

    Saturday, February 11, 2012 12:25 PM
  • Of course yo can set different variables dependig the value of your timer.

    Yo can do this as well by cheching if the timer is started or stopped as well by any declared value.
    Let me explain with an example:

    I wrote an application with a nautical horn assistance for vessesl.
    The signals are differen by good or poor visibilty.
    For goo visibility I need a timespan of 2 minutes fpr special singals and vessels and sometimes the reriod is only one minute.
    To give the user a feeback about singal status I check the horn-timer by an basicacal other thimer which shows bord time.

    This first timer checks: Is horn timer started or stopped. The result is a very simple if then loop. If honr-timer is working, a control label with a big point is green, else the label color is red.
    This is the first thing to do.

    The second thing was to handle different values.
    In my case ic could realise it by two ways.
    First method is to set a value e.g 1 Minunte as 6000 and two minutes as 12000.
    The timer event of my horn timer count up this variable by 1 per ech timer_event.
    The next step is also very easy. Check by a if then loop the actual timer status or use a do while loop.

    While the actual value < your declared value your application does nothing (keep its value), when the vlaue reaches the declared point of event handle the evente and set the value (counter to zero).

    In my application I used another method. When I start the event (horn signal) i calculate the time span to the actual time.
    So my application play the signal and set a new "alert time". While my local time < alert time, there happend nothing. When the actual time = alert time, the declared signal will played again and set a new alert time until the horn timer will stopped.

    Youe see, there are a lot of possibilities.

    Hope this is helpful to you.


    Liebe Grüße Stefan | Cheers Stefan I'm using VB 2008 Express Be a good forum member - mark posts that contain the answers to your questions or those that are helpful c# in vb Translator: http://www.developerfusion.com/tools/convert/csharp-to-vb/

    Saturday, February 11, 2012 12:29 PM
  • Ron

    I would take a more object oriented approach.

    Create a new class which inherits from Label.

    In this class add a timer which moves the location of the label any way you want.

    Handle the move event in your main form to display the location.

    Add a method to the class to start the movement and pass in the start and end locations to this method.

    That way if you want to do this with more than one label you don't have to duplicate any of the code.



    • Edited by Dave299 Saturday, February 11, 2012 12:53 PM
    Saturday, February 11, 2012 12:45 PM
  • The other answers that you have received make sense.  However, you also can do what you have stated in the original thread, thusly:

    'Add a class module and copy this code to it

    Public Class TimerWithArg
        Inherits Windows.Forms.Timer
        Public Event RTick(ByVal Arg As Long)
        Private somenumber As Long = 1
        Protected Overrides Sub OnTick(e As System.EventArgs)
            'MyBase.OnTick(e)   'this will keep the "normal Tick event from being propogated - remove the ' if you still want one
            RaiseEvent RTick(somenumber)
        End Sub
        Public Sub SetSomeNumberArg(ByVal Arg As Long)
            somenumber = Arg
        End Sub
    End Class

    Public Class Form1
        Private Sub TimerWithArg1_RTick(Arg As Long) Handles TimerWithArg1.RTick
            Me.Text = Arg.ToString
            TimerWithArg1.SetSomeNumberArg(Arg + 1)
        End Sub

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

        Private Sub TimerWithArg1_Tick(sender As Object, e As System.EventArgs) Handles TimerWithArg1.Tick
            Debug.Print("tick")
        End Sub
    End Class

    What I've done here is to create an inherited control that provides a new Event called RTick that allows an argument to be passed to the instantiating code (drop one on the form designer). If you run the simple example that I've shown (I didn't want to fiddle with the other code examples), you can see it in operation. You can add as many event arguments as you want, and manipulate these arguments either in the control or from other code.

    I think this is an academic exercise, but perhaps useful, none the less.

    Dick


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

    Saturday, February 11, 2012 6:55 PM
  • Use the Tag property:

    Public Class Form1
      Private Sub Form1_Load(ByVal sender As Object, ByVal e As EventArgs) Handles MyBase.Load
        Me.Size = New Size(500, 500)
        Timer1.Interval = 10
      End Sub
      Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As EventArgs) Handles Timer1.Tick
        Dim Pts() As Point = DirectCast(Timer1.Tag, Point())
        Dim ELoc As Point = Pts(1)
        Dim dX, dY As Double
        Static SLoc As Point = Pts(0)
        Static inc As Integer = 100
        dX = (ELoc.X - SLoc.X) / inc
        dY = (ELoc.Y - SLoc.Y) / inc
        SLoc.Y += CInt(dY)
        SLoc.X += CInt(dX)
        inc -= 1
        Label2.Text = SLoc.ToString
        Label1.Location = SLoc
        If inc = 0 Then Timer1.Stop()
      End Sub
      Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
        Timer1.Tag = New Point() {Label1.Location, New Point(400, 400)}
        Timer1.Start()
      End Sub
    End Class

    Saturday, February 11, 2012 7:18 PM
  • To everyone who has taken the trouble to respond to my question; Thank You.

    Each of you has certainly given me something to think about.

    John's Tag property looks interesting and Dave's suggestion of taking a more object oriented approach has already been implemented.

    The code I presented was only an example of what I was doing, the actual application is my version of PacMan in which I do create a Ghost Class which inherits PictureBox and other properties like .SLoc and .ELoc.

    I know the whole exercise is purely academic but I often try to re-invent the wheel. After all, VB is not ideally suited for fast action games.

    The actual resulting code from this exercise is only required to get 4 Ghosts from their Home to the Maze. I now do it inside a sub but I thought it might be interesting to do it inside a Timer event. And it certainly has proven interesting.

    Many thanks again to all. I'll take everything on board, try to digest it all then see if I can produce a satisfactory outcome. If not, at least the sub works well.

    Regards Ron

    Saturday, February 11, 2012 11:16 PM
  • IMO, I suggest you to use System.Timers.Timer class instead of the System.Windows.Forms.Timer class. Because it is much accurate ahd has more precision unit that is less than micro-second.  The alternative is to use StopWatch class which is the most accurate method to measure the time spent in programm codes.

    Just my two cents.


    My blog: http://soho-hsh.blogspot.com

    Sunday, February 12, 2012 12:27 AM
  • Ron,

    I don't see what you mean with Class variables.

    The class has properties like in this case Interval. You can reset it at any time you want in a method.

    (I normally put for this kind of cases also a stop at the beginning of the method which handles the timer event and do a start again at the end).


    Success
    Cor

    Sunday, February 12, 2012 11:15 AM
  • Thanks Cor,

    By Class variable I mean a variable that has Class scope. I don't know any other way to describe it.

    And I'm sorry but I'm not clear on the use of 'methods' as both you and Dave299 have suggested.

    Ron

    Tuesday, February 14, 2012 5:40 AM
  • I'm not clear on the use of 'methods' as both you and Dave299 have suggested

    A method is simply a Sub or a Function.

    Tuesday, February 14, 2012 11:39 AM
  • Thanks Dave,

    Obviously I've been using 'methods' all along and didn't realize it!

    But that is one of my weak points; getting familiar with the terminology.

    Ron

    Tuesday, February 14, 2012 9:44 PM
  • Ron 

    Sub and Functions are Methods

    Properties, Global Fields and Methods are members.


    Success
    Cor

    Tuesday, February 14, 2012 10:29 PM
  • No. There is no way.

    Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick

    This is the interface to the timer tick routine and as you can see, it's fixed and is unchageable.

    Renee


    "MODERN PROGRAMMING is deficient in elementary ways BECAUSE of problems INTRODUCED by MODERN PROGRAMMING." Me

    Wednesday, February 15, 2012 9:19 AM