Sam Sam - 26 days ago 13
Vb.net Question

Painting from a separate thread?

I'm currently working on a game that uses the graphics class to create all the pic's in the game, i'm also trying to paint the pic's from a separate thread to stop my main thread from freezing. But every time i try to run the program, the form appears with nothing on it and i get this error...


System.NullReferenceException: Object reference not set to an instance of an object.


at Single_Player.Form1.mainPaint(PaintEventArgs e) in c:\users\samuel\documents\visual studio 2012\Projects\Single_Player\Single_Player\Form1.vb:line 12



If my code did work i was expecting it to move an ellipse across the screen, anyway here's my code...

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
Dim paintT As New Threading.Thread(AddressOf mainPaint)
paintT.Start()
End Sub

Private Sub mainPaint(e As PaintEventArgs)
e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
e.Graphics.CompositingQuality = Drawing2D.CompositingQuality.HighQuality
Dim playerX As Integer = 0
Dim playerY As Integer = 206
Do While 0 / 0
e.Graphics.DrawRectangle(New Pen(Color.FromArgb(128, Color.Black)), 0, 0, 884, 24)
e.Graphics.FillRectangle(New SolidBrush(Color.FromArgb(128, Color.Black)), 0, 0, 884, 24)
e.Graphics.DrawString("Life: 5", New Font("DigifaceWide", 20, GraphicsUnit.Pixel), New SolidBrush(Color.FromArgb(191, Color.Green)), 2, 0)
e.Graphics.DrawString("Score: 0", New Font("DigifaceWide", 20, GraphicsUnit.Pixel), New SolidBrush(Color.FromArgb(191, Color.White)), 100, 0)
e.Graphics.FillEllipse(New SolidBrush(Color.FromArgb(128, Color.Blue)), playerX, playerY, 24, 24)
playerX = playerX + 1
playerY = playerY + 1
e.Graphics.Clear(Color.Transparent)
Threading.Thread.Sleep(50)
Loop
End Sub


Update (again)
My code so far (this time i've added a timer via the design window)...

Private Sub Form1_Shown(sender As Object, e As EventArgs) Handles Me.Shown
Timer1.Interval = 50
Timer1.Start()
End Sub

Private Sub mainBackgroundPB_Paint(sender As Object, e As PaintEventArgs) Handles Timer1.Tick
e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
e.Graphics.CompositingQuality = Drawing2D.CompositingQuality.HighQuality
e.Graphics.DrawRectangle(New Pen(Color.FromArgb(128, Color.Black)), 0, 0, 884, 24)
e.Graphics.FillRectangle(New SolidBrush(Color.FromArgb(128, Color.Black)), 0, 0, 884, 24)
e.Graphics.DrawString("Life: 5", New Font("DigifaceWide", 20, GraphicsUnit.Pixel), New SolidBrush(Color.FromArgb(191, Color.Green)), 2, 0)
e.Graphics.DrawString("Score: 0", New Font("DigifaceWide", 20, GraphicsUnit.Pixel), New SolidBrush(Color.FromArgb(191, Color.White)), 100, 0)
e.Graphics.FillEllipse(New SolidBrush(Color.FromArgb(128, Color.Blue)), playerX, playerY, 24, 24)
playerX = playerX + 1
playerY = playerY + 1
e.Graphics.Clear(Color.Transparent)
End Sub

Answer

You cannot paint in a worker thread, windows are fundamentally thread-unsafe. Your timer Tick event handler will crash and burn when the timer ticks. The Tick event doesn't have a PaintEventArgs argument.

Only the Paint event has those arguments, add that event and move your code. You can trigger the paint with the timer, make the event handler look like this:

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