[RESOLVED] PictureBox Image - Random Errors
I have a picturebox that I have assigned a bitmap to its image property.
I have this code that throws exceptions periodically. Typically when it is called there are 2500 points in the queue.
Periodically means I have to push the button that adds points(2500) to the queue as fast as possible for a period of time.
Code:
Dim pt As Point
Try
Do While newPTS.Count > 0
If newPTS.TryDequeue(pt) Then
PBbm.SetPixel(pt.X, pt.Y, PBbmDotColor)
End If
Loop
Catch ex As Exception
Dim s As String = String.Format("X: {0} Y:{1} {2}", pt.X, pt.Y, ex.Message)
AddToError(s)
End Try
I know that the points being set are within the bounds of the bitmap.
PBbm is the bitmap
newPTS is a queue of points
The errors
X: 446 Y:170 Object is currently in use elsewhere.
X: 34 Y:549 Object is currently in use elsewhere.
Re: PictureBox Image - Random Errors
Don't use System.Drawing.Bitmap.SetPixel, which is notoriously slow. It has to recreate the bitmap each time a pixel changes.
Instead try the FastPix method in my sig below. Treat the queue as an array of 32-bit integers, and the same for ARGB colors. The result can be as much as 100 times as fast.
BB
Re: PictureBox Image - Random Errors
You typically only see that error when doing multithreaded tasks. In this situation, is it possible that those points are being referenced in another thread?
Re: PictureBox Image - Random Errors
@boops - it is not slow though I bet it could be faster. Didn't see the code you were talking about though I did see you said it had error...
@dday - I'm guessing it is related to being multi threaded. That is the only place I change the bitmap. The stack is not in my code when it errors,
at System.Drawing.Image.get_Width()
at System.Drawing.Image.get_Size()
at System.Windows.Forms.PictureBox.ImageRectangleFromSizeMode(PictureBoxSizeMode mode)
at System.Windows.Forms.PictureBox.OnPaint(PaintEventArgs pe)
at System.Windows.Forms.Control.PaintWithErrorHandling(PaintEventArgs e, Int16 layer)
at System.Windows.Forms.Control.WmPaint(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)
Re: PictureBox Image - Random Errors
That makes me think, although I'm not positive, that perhaps the UI thread is using the object when you go to call SetPixel.
I'm wondering if you call SuspendLayout and then ResumeLayout before/after that call is made will stop throwing the exception. If so, it wouldn't solve your underlying issue rather it would only confirm my suspicion.
Re: PictureBox Image - Random Errors
Added a lock and made certain that I was only Invalidating the picture box in one location.
Code:
Private newPTS As New Concurrent.ConcurrentQueue(Of Point)
Private Sub AddPixelsToPict(count As Integer) 'can be called from any thread
If TRNG IsNot Nothing Then
For ct As Integer = 1 To count
Dim x As Integer = TRNG.Next(0, PBW) 'get random x and y
Dim y As Integer = TRNG.Next(0, PBH)
Dim pt As New Point(x, y)
newPTS.Enqueue(pt)
Next
SetPBbm()
End If
End Sub
Private Sub SetPBbm()
PBbmLock.WaitOne() 'lock for bitmap - Threading.AutoResetEvent
Dim pt As Point
Try
Do While newPTS.Count > 0
If newPTS.TryDequeue(pt) Then 'get a point
PBbm.SetPixel(pt.X, pt.Y, PBbmDotColor)
End If
Loop
Catch ex As Exception
Dim s As String = String.Format("X: {0} Y:{1} {2}", pt.X, pt.Y, ex.Message)
AddToError(s)
End Try
PBbmLock.Set()
End Sub
Every 100 ms this runs on the UI,
Code:
If PBbmLock.WaitOne(0) Then
Try
PictDots.Invalidate()
Catch ex As Exception
Dim s As String = "Invalidate"
AddToError(s)
End Try
PBbmLock.Set()
End If
Still getting the error...
Re: PictureBox Image - Random Errors
To create the error I was clicking a button that added several points and then holding down the enter key. This seems to have fixed it because I can't press enter continuously and I guess I can't click the button fast enough to cause the error.
Code:
Private addPtsTask As Task
Private Async Sub btnAddPts_Click(sender As Object, e As EventArgs) Handles btnAddPts.Click
If Monitoring.WaitOne(0) Then
If addPtsTask Is Nothing OrElse addPtsTask.Status = TaskStatus.RanToCompletion Then
btnAddPts.Enabled = False
addPtsTask = Task.Run(Sub() AddPixelsToPict(1000))
Await addPtsTask
addPtsTask = Nothing
btnAddPts.Enabled = True
End If
End If
End Sub