Search code examples
vb.netmultithreadinggraphicsthread-sleep

Making animation of flood fill in vb return object is currently used elsewhere using thread.sleep


I tried making animated flood fill (scanline algorithm) using sleep in vb. So it will show the order of pixels being colored. It will work for a little bit but then it will return object is currently used elsewhere

This is my code

Sub AnimatedRFRecursive(ByVal P As Point, ByVal C0 As Color, ByVal C1 As Color)

    Dim i, xL, xR As Integer
    Dim a As Point
    i = P.X
    While (i >= 0 AndAlso BMP.GetPixel(i, P.Y) = C0)
        Thread.Sleep(10)
        BMP.SetPixel(i, P.Y, C1)
        PictureBox1.Invoke(New Action(Sub() PictureBox1.Image = BMP))
        i -= 1
    End While
    xL = i + 1
    i = P.X + 1
    While (i < 500 AndAlso BMP.GetPixel(i, P.Y) = C0)
        Thread.Sleep(10)
        BMP.SetPixel(i, P.Y, C1)
        PictureBox1.Invoke(New Action(Sub() PictureBox1.Image = BMP))
    End While
    xR = i - 1
    For i = xL To xR
        If (P.Y < 349 AndAlso BMP.GetPixel(i, P.Y + 1) = C0) Then
            a.X = i
            a.Y = P.Y + 1

            AnimatedRFRecursive(a, C0, C1)
        End If
        If (P.Y > 0 AndAlso BMP.GetPixel(i, P.Y - 1) = C0) Then
            a.X = i
            a.Y = P.Y - 1
            AnimatedRFRecursive(a, C0, C1)
        End If
    Next
End Sub

This is how I call it

Dim thr As New Threading.Thread(Sub() AnimatedRFRecursive(point, C, Color))
thr.Start()

Please tell me where did I do wrong or if you have any other method that works also do. Thank you


Solution

  • You have multiple threads that need to access the same object (BMP). This will require that you synchronize access to the BMP object.

    Please note that your original code has two magic numbers (500 and 349) that I assumed correspond to the bitmap's width and height. Change the usage of the variables in the code below if this assumption if incorrect.

    Private BMP As Bitmap
    Private BMPKey As New Object
    Private Sub UpdatePictureBox()
        PictureBox1.Invoke(Sub()
                                    SyncLock BMPKey
                                        Dim oldBM As Image = PictureBox1.Image
                                        PictureBox1.Image = New Bitmap(BMP)
                                        If oldBM IsNot Nothing Then oldBM.Dispose()
                                    End SyncLock
    
                                    End Sub)
    
    End Sub
    
    Private Function GetBMPPixel(x As Int32, y As Int32) As Color
        SyncLock BMPKey
            Return BMP.GetPixel(x, y)
        End SyncLock
    End Function
    
    Private Sub SetBMPPixel(x As Int32, y As Int32, c As Color)
        SyncLock BMPKey
            BMP.SetPixel(x, y, c)
        End SyncLock
    End Sub
    
    Sub AnimatedRFRecursive(ByVal P As Point, ByVal C0 As Color, ByVal C1 As Color)
    
         Dim i, xL, xR As Integer
         Dim a As Point
         i = P.X
         Dim width As Int32
         Dim height As Int32
         SyncLock BMPKey
            width = BMP.Width       ' original code magic number of 500 
            height = BMP.Height ' original code magic number of 349  
         End SyncLock
         While (i >= 0 AndAlso GetBMPPixel(i, P.Y).ToArgb = C0.ToArgb)
              Thread.Sleep(10)
              SetBMPPixel(i, P.Y, C1)
              UpdatePictureBox()
              i -= 1
         End While
         xL = i + 1
         i = P.X + 1
         While (i < width - 1 AndAlso GetBMPPixel(i, P.Y).ToArgb = C0.ToArgb)
              Thread.Sleep(10)
              SetBMPPixel(i, P.Y, C1)
              UpdatePictureBox()
         End While
         xR = i - 1
         For i = xL To xR
              If (P.Y < height - 1 AndAlso GetBMPPixel(i, P.Y + 1).ToArgb = C0.ToArgb) Then
                    a.X = i
                    a.Y = P.Y + 1
    
                    AnimatedRFRecursive(a, C0, C1)
              End If
              If (P.Y > 0 AndAlso GetBMPPixel(i, P.Y - 1).ToArgb = C0.ToArgb) Then
                    a.X = i
                    a.Y = P.Y - 1
                    AnimatedRFRecursive(a, C0, C1)
              End If
         Next
    End Sub