Question Multi Threading A Timer To Change Picture Box Image

madaxe

Member
Joined
Mar 18, 2008
Messages
16
Programming Experience
1-3
I'm creating a simple internet radio player using the windows media player control. And I want to search the users pictures folder for images and display them as a slide show in the form. This is easy but i have found that the sound becomes a little choppy when i add a timer.

I want to create a second thread that builds a timer i have my code below but it does not work.

If I dont use the thread and call the sub routine ticker it works fine, but the sound is still a little choppy

please help madaxe

VB.NET:
    Private Sub Form1_Load(ByVal sender As System.Object, _
                           ByVal e As System.EventArgs) _
                           Handles MyBase.Load

        Dim MyThread As System.Threading.Thread
        MyThread = New System.Threading.Thread(AddressOf Me.Ticker)
        MyThread.Start()

    End Sub

    Public Sub Ticker()

        Dim MyTimer As New Timer
        MyTimer.Interval = 100
        MyTimer.Start()

        AddHandler MyTimer.Tick, AddressOf DoOnTicker

    End Sub

    Public Sub DoOnTicker()

        Dim MyBitMap(10) As Bitmap
        MyBitMap(1) = DirectCast(My.Resources.Image1, Bitmap)
        MyBitMap(2) = DirectCast(My.Resources.Image2, Bitmap)
        MyBitMap(3) = DirectCast(My.Resources.Image3, Bitmap)
        MyBitMap(4) = DirectCast(My.Resources.Image4, Bitmap)
        MyBitMap(5) = DirectCast(My.Resources.Image5, Bitmap)
        MyBitMap(6) = DirectCast(My.Resources.Image6, Bitmap)
        MyBitMap(7) = DirectCast(My.Resources.Image7, Bitmap)
        MyBitMap(8) = DirectCast(My.Resources.Image8, Bitmap)
        MyBitMap(9) = DirectCast(My.Resources.Image9, Bitmap)
        MyBitMap(10) = DirectCast(My.Resources.Image10, Bitmap)

        ImageNumber = ImageNumber + 1

        If ImageNumber = 11 Then

            ImageNumber = 1

        End If

        PBox.Image = ResizeImage(MyBitMap(ImageNumber))


    End Sub
 
You are creating 10 new Bitmap objects 10 times every second. You should be creating Bitmap objects once and once only. You don't need multit-hreading for this at all.

1. Add the Timer to your form in the designer. Set it's Interval property appropriately and set Enabled to False.
2. In the Load event handler of the form, create your Image array and start the Timer.
3. In the Tick event handler of the Timer, advance the image number and display that Image only.
VB.NET:
Private imageIndex As Integer
Private images As Image()

Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    Me.images = New Image() {Me.ResizeImage(My.Resources.Image1), _
                             Me.ResizeImage(My.Resources.Image2), _
                             Me.ResizeImage(My.Resources.Image3), _
                             Me.ResizeImage(My.Resources.Image4), _
                             Me.ResizeImage(My.Resources.Image5), _
                             Me.ResizeImage(My.Resources.Image6), _
                             Me.ResizeImage(My.Resources.Image7), _
                             Me.ResizeImage(My.Resources.Image8), _
                             Me.ResizeImage(My.Resources.Image9), _
                             Me.ResizeImage(My.Resources.Image10)}

    Me.Timer1.Start()
End Sub

Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
    Me.imageIndex = (Me.imageIndex + 1) Mod 10
    Me.PictureBox1.Image = Me.images(Me.imageIndex)
End Sub
 
This is my final code for the ticker is there a better way to handle the second part?

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

        Dim MyFiles As Collections.ObjectModel.ReadOnlyCollection(Of String)
        MyFiles = FileIO.FileSystem.GetFiles(My.Computer.FileSystem.SpecialDirectories.MyPictures, _
                                             FileIO.SearchOption.SearchAllSubDirectories, "*.bmp", "*.jpg", "*.tif", "*.png")


        ImageNumber = ImageNumber + 1

        If MyFiles.Count = 0 Then

            Me.MyImageIndex = (Me.MyImageIndex + 1) Mod 10
            Me.PBox.Image = Me.MyImagesArray(Me.MyImageIndex)

        Else

            If ImageNumber = MyFiles.Count Then

                ImageNumber = 1

            End If

            Dim MyUserBitmap As New Bitmap(MyFiles.Item(ImageNumber))

            PBox.Image = ResizeImage(MyUserBitmap)

        End If

    End Sub
 
That code doesn't really make sense. Please explain EXACTLY how you want your app to behave. Only if you fully understand the desired behaviour can you write code to implement that behaviour.
 
I have it working, but im always looking for better ways to do things,

The code does two things, it writes URL's to a SQLite database, uses the Windows Media Player control to play the urls, and either shows the images in the users pictures folder or uses the images in the resources.

VB.NET:
Public Class Form1

    Public MyImageIndex As Integer
    Public MyImagesArray As Image()
    Public MyFiles As Collections.ObjectModel.ReadOnlyCollection(Of String)
    Public ImageNumber As Integer = 1
    Public PlayingURL As String = ""
    Public SQLConnectionString = ""
    Public SQLconnect As New SQLite.SQLiteConnection()
    Public SQLcommand As SQLite.SQLiteCommand


    Private Sub Form1_Load(ByVal sender As System.Object, _
                           ByVal e As System.EventArgs) _
                           Handles MyBase.Load

        Initialize()

        Me.Timer1.Start()

    End Sub

    Private Sub Initialize()

        Dim DestinationDir As String = "\TATA\"
        Dim MyDedicatedFolder As String = Environment.GetFolderPath _
        (Environment.SpecialFolder.CommonApplicationData)

        If System.IO.Directory.Exists(MyDedicatedFolder & DestinationDir) = False Then

            System.IO.Directory.CreateDirectory(MyDedicatedFolder & DestinationDir)

            CopyResourceData(MyDedicatedFolder & DestinationDir)

        Else

            CopyResourceData(MyDedicatedFolder & DestinationDir)

        End If

        PopulateComboBox()

        MyFiles = FileIO.FileSystem.GetFiles(My.Computer.FileSystem.SpecialDirectories.MyPictures, _
                                     FileIO.SearchOption.SearchAllSubDirectories, "*.bmp", "*.jpg", "*.tif", "*.png")

        Me.MyImagesArray = New Image() {Me.ResizeImage(My.Resources.Image1), _
                                 Me.ResizeImage(My.Resources.Image2), _
                                 Me.ResizeImage(My.Resources.Image3), _
                                 Me.ResizeImage(My.Resources.Image4), _
                                 Me.ResizeImage(My.Resources.Image5), _
                                 Me.ResizeImage(My.Resources.Image6), _
                                 Me.ResizeImage(My.Resources.Image7), _
                                 Me.ResizeImage(My.Resources.Image8), _
                                 Me.ResizeImage(My.Resources.Image9), _
                                 Me.ResizeImage(My.Resources.Image10)}

        PlayingURL = CB_URL_List.Items(0).ToString
        CB_URL_List.Text = PlayingURL
        WMPlayer.URL = PlayingURL
        PBox.Image = ResizeImage(My.Resources.Image1)
        BT_URL_REMOVE.Enabled = False

    End Sub

    Private Sub CopyResourceData(ByVal MyDedicatedFolder As String)

        Dim FilePath As String = MyDedicatedFolder & "RadioStationURLDatabase.db3"

        If Not My.Computer.FileSystem.FileExists(FilePath) Then

            System.IO.File.WriteAllBytes(FilePath, My.Resources.RadioStationURLDatabase)

        End If

        Dim MyBitMap(10) As Bitmap
        MyBitMap(1) = DirectCast(My.Resources.Image1, Bitmap)
        MyBitMap(2) = DirectCast(My.Resources.Image2, Bitmap)
        MyBitMap(3) = DirectCast(My.Resources.Image3, Bitmap)
        MyBitMap(4) = DirectCast(My.Resources.Image4, Bitmap)
        MyBitMap(5) = DirectCast(My.Resources.Image5, Bitmap)
        MyBitMap(6) = DirectCast(My.Resources.Image6, Bitmap)
        MyBitMap(7) = DirectCast(My.Resources.Image7, Bitmap)
        MyBitMap(8) = DirectCast(My.Resources.Image8, Bitmap)
        MyBitMap(9) = DirectCast(My.Resources.Image9, Bitmap)
        MyBitMap(10) = DirectCast(My.Resources.Image10, Bitmap)

        Dim Index As Integer = 1
        For Index = 1 To 10

            MyBitMap(Index).Save(MyDedicatedFolder & "Image" & Index & ".bmp")

        Next

        SQLConnectionString = "Data Source=" & FilePath

    End Sub

    Private Sub PopulateComboBox()

        CB_URL_List.Items.Clear()

        Dim SQLconnect As New SQLite.SQLiteConnection()
        Dim SQLcommand As SQLite.SQLiteCommand

        SQLconnect.ConnectionString = SQLConnectionString
        SQLconnect.Open()

        SQLcommand = SQLconnect.CreateCommand
        SQLcommand.CommandText = "SELECT * FROM RadioStationURLTable ORDER BY Usage DESC"

        Dim SQLreader As SQLite.SQLiteDataReader = SQLcommand.ExecuteReader()
        Dim MyString As String = ""

        While SQLreader.Read()

            MyString = String.Format("{0}", SQLreader(1))


            CB_URL_List.Items.Add(MyString)

        End While

        SQLcommand.Dispose()
        SQLconnect.Close()

    End Sub

    Private Sub BT_ADD_URL_Click(ByVal sender As System.Object, _
                                 ByVal e As System.EventArgs) _
                                 Handles BT_ADD_URL.Click

        SQLconnect.ConnectionString = SQLConnectionString
        SQLconnect.Open()
        SQLcommand = SQLconnect.CreateCommand

        SQLcommand.CommandText = _
        "INSERT INTO RadioStationURLTable(URL,Usage) VALUES('" _
        & CB_URL_List.Text & "','" & 1 & "')"

        SQLcommand.ExecuteNonQuery()
        SQLcommand.Dispose()
        SQLconnect.Close()

        PlayingURL = CB_URL_List.Text.ToString
        CB_URL_List.Items.Add(PlayingURL)
        WMPlayer.URL = PlayingURL

    End Sub

    Private Sub CB_URL_List_Click(ByVal sender As Object, ByVal e As System.EventArgs) Handles CB_URL_List.Click

        BT_URL_REMOVE.Enabled = True

    End Sub

    Private Sub CB_URL_List_SelectedValueChanged(ByVal sender As Object, _
                                                 ByVal e As System.EventArgs) _
                                                 Handles CB_URL_List.SelectedValueChanged

        If Not PlayingURL = CB_URL_List.Text.ToString Then

            PlayingURL = CB_URL_List.Text.ToString
            WMPlayer.URL = PlayingURL

            SQLconnect.ConnectionString = SQLConnectionString
            SQLconnect.Open()
            SQLcommand = SQLconnect.CreateCommand

            SQLcommand.CommandText = _
            "SELECT * FROM RadioStationURLTable WHERE URL = '" & _
            PlayingURL & "'"

            Dim SQLreader As SQLite.SQLiteDataReader = SQLcommand.ExecuteReader()
            Dim MyInteger As Integer = 0

            While SQLreader.Read()

                MyInteger = CInt(String.Format("{0}", SQLreader(2)))

                MyInteger = MyInteger + 1

            End While

            SQLreader.Close()

            SQLcommand.CommandText = _
            "UPDATE RadioStationURLTable SET Usage = '" & _
            MyInteger & "' WHERE URL = '" _
            & CB_URL_List.Text.ToString & "'"

            SQLcommand.ExecuteNonQuery()

            SQLcommand.Dispose()
            SQLconnect.Close()

            PopulateComboBox()
            PlayingURL = PlayingURL
            CB_URL_List.Text = PlayingURL
            WMPlayer.URL = PlayingURL

        End If

    End Sub

    Private Sub BT_URL_CLEAR_Click(ByVal sender As System.Object, _
                                   ByVal e As System.EventArgs) _
                                   Handles BT_URL_CLEAR.Click

        CB_URL_List.Text = ""

    End Sub

    Private Sub BT_URL_REMOVE_Click(ByVal sender As System.Object, _
                                    ByVal e As System.EventArgs) _
                                    Handles BT_URL_REMOVE.Click

        SQLconnect.ConnectionString = SQLConnectionString
        SQLconnect.Open()

        SQLcommand = SQLconnect.CreateCommand
        SQLcommand.CommandText = _
        "DELETE FROM RadioStationURLTable WHERE URL = '" & _
        CB_URL_List.Text.ToString & "'"

        SQLcommand.ExecuteNonQuery()
        SQLcommand.Dispose()

        SQLconnect.Close()

        PopulateComboBox()

        PlayingURL = CB_URL_List.Items(0).ToString
        CB_URL_List.Text = PlayingURL
        WMPlayer.URL = PlayingURL

    End Sub

    Private Function ResizeImage(ByVal bm As Bitmap) As Bitmap

        Dim x As Int32 = PBox.Width
        Dim y As Int32 = PBox.Height

        Dim width As Integer = Val(x)
        Dim height As Integer = Val(y)

        Dim thumb As New Bitmap(width, height)

        Dim g As Graphics = Graphics.FromImage(thumb)

        g.InterpolationMode = Drawing2D.InterpolationMode.HighQualityBicubic
        g.DrawImage(bm, New Rectangle(0, 0, width, height), _
                    New Rectangle(0, 0, bm.Width, bm.Height), GraphicsUnit.Pixel)
        g.Dispose()

        Return thumb

        bm.Dispose()
        thumb.Dispose()

    End Function

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

        ImageNumber = ImageNumber + 1

        If MyFiles.Count = 0 Then

            MyImageIndex = (MyImageIndex + 1) Mod 10
            PBox.Image = MyImagesArray(MyImageIndex)

        Else

            If ImageNumber = MyFiles.Count Then

                ImageNumber = 1

            End If

            Dim MyUserBitmap As New Bitmap(MyFiles.Item(ImageNumber))

            PBox.Image = ResizeImage(MyUserBitmap)

        End If

    End Sub

End Class
 

Latest posts

Back
Top