Moving rectangles via timer control.

Cheetah

Well-known member
Joined
Oct 12, 2006
Messages
232
Programming Experience
Beginner
Hi there,

I am trying to create a user control that does a slide show of images, but when I run it - it doesn't move the images. What am I doing wrong?

I am not to familiar with the Paint and Graphics class' so if its anything to do with that, which i suspect it is - go slow :)

VB.NET:
Public Class UserControl1

    Private _imageList, _backgroundImages As List(Of String)
    Dim rectList As New List(Of Rectangle)

    Public Sub New(ByVal imageList As List(Of String), ByVal location As Drawing.Point, ByVal backgroundImages As List(Of String), ByVal size As Size)

        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        _imageList = imageList
        _backgroundImages = backgroundImages

        Me.Location = location
        Me.Size = size

        Me.BackgroundImage = Image.FromFile(backgroundImages(0), True)

        For i As Integer = 0 To imageList.Count - 1

            Dim xCor As Integer = 150 + (i * 135)
            Dim newRect As New Rectangle(xCor, 15, 120, 120)

            rectList.Add(newRect)

        Next

    End Sub

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

        For Each rect As Rectangle In rectList

            rect.X -= 2

        Next

        Me.Refresh()

    End Sub

    Private Sub UserControl1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Timer1.Enabled = True
    End Sub

    Private Sub UserControl1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint

        For i As Integer = 0 To rectList.Count - 1

            e.Graphics.DrawImage(Image.FromFile(_imageList(i)), rectList(i))

        Next

    End Sub
End Class

I think the Paint methods are actually working as when I turn "DoubleBuffered" property off - you can see the refresh.

Thanks.
 

Attachments

  • WindowsApplication1.zip
    52.7 KB · Views: 21
Last edited:
This is a very bad idea:
VB.NET:
e.Graphics.DrawImage(Image.FromFile(_imageList(i)), rectList(i))
That means that every time the control is painted you are creating an Image object for every file in the list and never disposing any of them. Not only is that slow, it's also creating a resource leak. What you should be doing is creating all the Image objects once and once only, then storing them in an array. When you need to draw the Images you then get those Image objects directly from that array, instead of discarding the existing Images without destroying them, thus leaking resources, and then creating new ones, thus impacting performance.

Fix that first, and if you still have issues then you need to confirm that all your Images are actually being drawn where you expect them to.
 
Thanks for your input - I have changed my code to take into account your points, but it still doesn't move the images (rectangles).

The rectangles show in the initial place correctly.

VB.NET:
Public Class UserControl1

    Private _backgroundImages As List(Of String)
    Private _imageList As New List(Of Image)
    Dim rectList As New List(Of Rectangle)

    Public Sub New(ByVal imageList As List(Of String), ByVal location As Drawing.Point, ByVal backgroundImages As List(Of String), ByVal size As Size)

        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        For Each imageURL As String In imageList
            _imageList.Add(Image.FromFile(imageURL, True))
        Next

        _backgroundImages = backgroundImages

        Me.Location = location
        Me.Size = size

        Me.BackgroundImage = Image.FromFile(backgroundImages(0), True)

        For i As Integer = 0 To imageList.Count - 1

            Dim xCor As Integer = 150 + (i * 135)
            Dim newRect As New Rectangle(xCor, 15, 120, 120)

            rectList.Add(newRect)

        Next

    End Sub

    Public Overloads Sub Dispose()

        For Each refImage As Image In _imageList
            refImage.Dispose()
            refImage = Nothing
        Next

        _imageList.Clear()

    End Sub

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

        For Each rect As Rectangle In rectList

            Dim location As System.Drawing.Point = rect.Location
            Dim xCor As Int64 = rect.Location.X - 2
            rect.Location = New Drawing.Point(xCor, 20)

        Next
        Me.Refresh()

    End Sub

    Private Sub UserControl1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
        Timer1.Enabled = True
    End Sub

    Private Sub UserControl1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles Me.Paint

        For i As Integer = 0 To rectList.Count - 1

            e.Graphics.DrawImage(_imageList(i), rectList(i))
            e.Graphics.DrawRectangle(Pens.Black, rectList(i))

        Next

    End Sub

End Class

I am under the impression that the Me.Refresh() line of code isn't raising the Paint Event, because when I put a debug stop there - it never seems to trigger.

Thanks.
 
This is done using the invalidate() method. You can use its overloads to invalidate an area of the control without forcing a repaint of the whole control.
 
This is done using the invalidate() method. You can use its overloads to invalidate an area of the control without forcing a repaint of the whole control.
What do you suppose Refresh does? All it does is call Invalidate, then Update. It is the Update method that actually causes the Paint event to be raised. The Invalidate method just tells the control which areas to redraw when Update is called.
 
Back
Top