שתף באמצעות


Moving Control with Timer to a Certain Location [VB.Net]

Question

Monday, July 4, 2016 3:47 AM

How can I move a control, such as a Picturebox, smoothly from its location to another specified location on the form using a Timer? Is there a simpler way to make this transition visible than to experiment with PictureBox.Top, PictureBox.Left, and others? I want to be able to see the control moving across the form for at least a second.

Bgeo25

All replies (6)

Monday, July 4, 2016 5:34 AM ✅Answered | 1 vote

Well if the PictureBox was at point(500, 500) then depending on how you determine the next point to move the PictureBox too you could set a global variable for that.

Dim PboxPoint as Point

In some code PBoxPoint = New Point(10, 600)

In Timer sub with interval set to 1 or 10 or whatever you will either need to subtract or add 1 I suppose to the PictureBoxes Location values until the values in PBoxPoints x and y coordinates are reached.

However that will not work real well since the new x and y coordinates to move the PictureBox too could have a great difference between them so the PictureBox may not move linearly. It may move up 10 and left 300 which would cause a strange issue since it would be up 10 and left 10 then just left to 300.

Since a controls location is a point using integer then pointf using single can not be used.

I can provide some code, I will update this post, for doing what you desire but there's probably simpler code for performing that. Be a few minutes.

Update: You can see in the animated .Gif that the control can not move directly from point A to point B since a Point uses integers which have no decimal type capability so that an accurate direction can occur. Somebody else may be able to provide other math which can perform for integer values better I suppose.

One thing you could do is make the PictureBox visible to false at the start of the move. Place the PictureBox at the new location. Draw the image in the PictureBox onto the Form moving the drawing until it gets to the new PictureBox location then quit drawing the image and set the PictureBox visible to true. That way PointF can be used for drawing the image on the Form and the image will move nicely and the code would obviously need to be altered to do that.

You can see in the bottom animated .Gif that the PictureBox's movement towards the end is erratic due to not being able to use singles for its x and y coordinates.

Option Strict On

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.DoubleBuffered = True
        Me.Location = New Point(CInt((Screen.PrimaryScreen.WorkingArea.Width / 2) - (Me.Width / 2)), CInt((Screen.PrimaryScreen.WorkingArea.Height / 2) - (Me.Height / 2)))
        Timer1.Interval = 10
    End Sub

    Dim PBoxMoving As Boolean = False
    Dim PBoxOldLocation As Point
    Dim PBoxNewLocation As Point
    Dim Rect As Rectangle
    Dim DistanceToUse As Single = 2

    Private Sub Form1_MouseDown(sender As Object, e As MouseEventArgs) Handles Me.MouseDown
        If PBoxMoving = False Then
            PBoxOldLocation = PictureBox1.Location
            PBoxNewLocation = e.Location
            Rect = New Rectangle(New Point(PBoxNewLocation.X - CInt(Math.Ceiling(CDec(DistanceToUse))), PBoxNewLocation.Y - CInt(Math.Ceiling(CDec(DistanceToUse)))), New Size(CInt(Math.Ceiling(CDec(DistanceToUse * 2))), CInt(Math.Ceiling(CDec(DistanceToUse * 2)))))
            PBoxMoving = True
            Timer1.Start()
        End If
    End Sub

    Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
        Dim PBL As PointF = MathHelp.GetPointToward(New PointF(PBoxOldLocation.X, PBoxOldLocation.Y), New PointF(PBoxNewLocation.X, PBoxNewLocation.Y), DistanceToUse)
        PictureBox1.Location = New Point(CInt(PBL.X), CInt(PBL.Y))
        Me.Update()
        PBoxOldLocation = PictureBox1.Location
        If Rect.Contains(PictureBox1.Location) Then
            Timer1.Stop()
            PictureBox1.Location = PBoxNewLocation
            PBoxMoving = False
        End If
    End Sub

    ' Below class was created by Reed Kimble for a game in one of this forums threads a while ago.

    Public NotInheritable Class MathHelp
        Public Const TWO_PI As Single = Math.PI * 2

        Protected Sub New()
        End Sub

        Public Shared Function GetDistance(ByVal source As PointF, ByVal target As PointF) As Single
            Dim squareX As Double = CDbl(target.X - source.X)
            squareX *= squareX
            Dim squareY As Double = CDbl(target.Y - source.Y)
            squareY *= squareY
            Return CSng(Math.Sqrt(squareX + squareY))
        End Function

        Public Shared Function GetRadiansTo(ByVal source As PointF, ByVal target As PointF) As Single
            Return WrapAngle(CSng(Math.Atan2(target.Y - source.Y, target.X - source.X)))
        End Function

        Public Shared Function GetPointToward(ByVal source As PointF, ByVal target As PointF, ByVal distance As Single) As PointF
            Dim angle As Single = GetRadiansTo(source, target)
            Return source + New SizeF(CSng(Math.Cos(angle) * distance), CSng(Math.Sin(angle) * distance))
        End Function

        Public Shared Function WrapAngle(ByVal radians As Single) As Single
            While radians < -Math.PI
                radians += TWO_PI
            End While
            While radians > Math.PI
                radians -= TWO_PI
            End While
            Return radians
        End Function
    End Class

End Class

La vida loca


Monday, July 4, 2016 4:11 AM

The Forms double buffered property may need to be set to true to stop flickering.

You don't explain how you determine where to move the PictureBox to on the Form.

The below thread may have some code in timer events that is relevant to what you want to do.

Make the contents of a panel fade

La vida loca


Monday, July 4, 2016 4:27 AM

The Forms double buffered property may need to be set to true to stop flickering.

You don't explain how you determine where to move the PictureBox to on the Form.

The below thread may have some code in timer events that is relevant to what you want to do.

Make the contents of a panel fade

La vida loca

I'll be more specific with an example. If I have a PictureBox with location (62, 62) on a form, I want to accomplish moving the PictureBox to new location (100, 200). In every case, I will already know the destination point. I could change the location by

PictureBox1.Location = New Point(100, 200)

but that will move the PictureBox instantaneously. I want to be able to see the control gradually moving from the (62, 62) to (100, 200). I assume a Timer would help in this case, but is there a faster/more efficient way than using PictureBox.Left += (something) or PictureBox.Top += (something) in a Timer?

Bgeo25


Monday, July 4, 2016 5:25 AM | 1 vote

If you are interested in alternatives, then consider another kind of VB.NET applications: WPF or UWP. There are a series of embedded animation effects, which do not need explicit timers (https://msdn.microsoft.com/en-us/library/ms752312(v=vs.100).aspx).


Monday, July 4, 2016 5:32 AM | 1 vote

If I have a PictureBox with location (62, 62) on a form, I want to accomplish moving the PictureBox to new location (100, 200). In every case, I will already know the destination point.

You need to calculate the x distance and the Y distance that you need to move - a simple subtract of the respective values of the two positions will give that.

Then you need to come up with a figure for the number of steps that you want to take and the time interval between each step.  For instance, ten steps at 100ms each will take one second to do the move.

Divide your X and Y distances by ten to get the number of pixels to move in each step.  Set the timer interval to 100ms, and start the timer.  At each timer tick, move the picturebox by the calculated number of pixels, calculated separately for X and Y.  When ten ticks have occurred (you should use a counter, position information may not be exact) stop the timer and position the control at the destination exactly. 


Tuesday, July 5, 2016 6:55 AM

Using acceleration and decelleration on moving objects provides a better look. A 'snap' movement requires a uniform acceleration for most of the movement, then a severe decelleration to bring the object to a stop.

Experiment with writing code to produce a list of whole number steps, which increase and decrease in magnitude. The 'sum of' all the individual steps make up the total movement.

For example: Say you want to move an object 100 pixels. 5 + 10 + 15 + 20 + 25 + 15 + 10 = 100

BumperSticker: Amateurs built the Ark, Professionals built the Titanic