NatJ NatJ - 6 months ago 16
Vb.net Question

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

Answer

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