Search code examples
vb.netmultithreadingbackground-thread

Background Thread slowing Main UI Thread visual basic


I would like to show a gif inside a Picture Box for 2 seconds on a separate thread from the main thread. I am running a timer that moves a Picture Box with an Image on the main thread.

To test I created a Picture Box and added same Image I start the background thread with a button click. The obvious ERROR or Issue is that the supposed Background Thread slows the Main Thread.

Creating and Implementing a Threads seems to offer two options BackgroundWorker and Task.Run.

I looked at this Code Magazine Article which offered way more options than I am grasping: Code Magazine Article

Also looked at this Article could not convert the C# code to VB YES I used a code converter: Stephen Cleary

My code is posted below for the Background Thread No need to post the Timer Tick Code.

Question what am I missing or what am I doing wrong OR is this just not possible?

Private Sub myThreadMethod()
    'Await
    'Async
    Dim myThread As New Thread(AddressOf myThreadMethod)
    myThread.IsBackground = True

    myThread.Start()
    If Me.InvokeRequired = True Then
        Me.Invoke(Sub()
                      'PbT.Location = New Point(128, 132)
                      PbT.Left -= 1
                      PbT.Top += 2
                  End Sub)
        'If PbT.Bounds.IntersectsWith(btnBot.Bounds) Then
        'TextBox1.Invoke(Sub() TextBox1.Text =
    End If
    If PbT.Location.Y > 500 Then
        PbT.Invoke(Sub() PbT.Location = New Point(350, 230))
        Thread.Sleep(9000)
        myThread.Abort()
    End If

End Sub

Answer to Question was added to by Craig and Answered by James_Duh


Public Class frmStart

Dim running As Boolean = False
Dim stopWatch As Stopwatch = New Stopwatch

Private Sub frmStart_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
    Cursor.Clip = New Rectangle(Me.Location, Me.Size)
    btnLPad.Left = e.X
    btnCPad.Left = e.X + 28
    btnRPad.Left = e.X + 56
End Sub

Private Sub tmrMove_Tick(sender As Object, e As EventArgs) Handles tmrMove.Tick

    Static direction As New Point(0, 4)

    Static endTime As DateTime = DateTime.Now.AddYears(1)
    If DateTime.Now > endTime Then
        PbT.Visible = False
        endTime = DateTime.Now.AddYears(1)
    End If

    If _buttons.All(Function(x) x.Button.Visible = False) Then
        pbOne.Top = 300
        PbT.Visible = False
        tbAns.Visible = True

        stopWatch.Stop()
        Dim ts = stopWatch.Elapsed
        Dim elapsedTime = $"{ts.Minutes:0} Min {ts.Seconds:00} Sec"
        tbAns.Text = elapsedTime

        running = False
        direction = New Point(0, 4)

        tmrMove.Stop()
        MsgBox("You Win")
        stopWatch.Reset()
        '================
        tbAns.Visible = False
        ResetButtons()

    End If

    If pbOne.Bounds.IntersectsWith(btnLPad.Bounds) Then
        direction = New Point(-2, -3)
    End If
    If pbOne.Bounds.IntersectsWith(btnRight.Bounds) Then
        Static spC As Integer = 1
        spC += 1
        direction = If(spC Mod 2 = 0, New Point(-3, 2), New Point(-5, 1))
    End If

    If pbOne.Bounds.IntersectsWith(btnLeft.Bounds) Then
        direction = New Point(4, 2)
    End If

    If pbOne.Bounds.IntersectsWith(btnCPad.Bounds) Then
        direction = New Point(direction.X, -4)
    End If

    If pbOne.Bounds.IntersectsWith(btnRPad.Bounds) Then
        Static spA As Integer = 1
        spA += 1
        direction = If(spA Mod 2 = 0, New Point(1, -5), New Point(-3, -4))
    End If

    If pbOne.Bounds.IntersectsWith(btnTop.Bounds) Then
        Static spE As Integer = 1
        spE += 1
        direction = If(spE Mod 2 = 0, New Point(-3, 2), New Point(4, 2))
    End If

    If pbOne.Bounds.IntersectsWith(btnBot.Bounds) Then
        tmrMove.Stop()
        running = False
        pbOne.Top = 200
        PbT.Visible = False
        MsgBox("Press S to Start")
    End If

    pbOne.Left += direction.X
    pbOne.Top += direction.Y

    For Each x In _buttons
        If pbOne.Bounds.IntersectsWith(x.Button.Bounds) Then
            endTime = DateTime.Now.AddSeconds(2.0)
            x.Button.Visible = False
            x.Button.Location = New Point(350, -30)
            PbT.Location = New Point(x.Location.X + 20, 31)
            PbT.Visible = True
            direction = New Point(3, 3)
        End If
    Next
End Sub
Private Sub frmStart_KeyDown(ByVal sender As Object, ByVal e As System.Windows.Forms.KeyEventArgs) Handles Me.KeyDown

    If running AndAlso e.KeyCode = Keys.P Then
        tmrMove.Stop()
    End If

    If e.KeyCode = Keys.S Then

        If Not running Then
            stopWatch.Start()
            running = True
        End If

        tmrMove.Interval = 1
        tmrMove.Start()

    End If

End Sub
Public Sub frmStart_KeyPress(sender As Object, e As KeyPressEventArgs) Handles Me.KeyPress
    'Form Property KeyPreview needs to be set to True
    '=================================================

    If Asc(e.KeyChar) = 27 Then

        Const message As String = "YES" & "   Exit Program" + vbCrLf + vbNewLine + "NO" & "     Read Directions"
        Const caption As String = "Exit OR Return"

        Dim result = MessageBox.Show(message, caption, MessageBoxButtons.YesNo, MessageBoxIcon.Question)

        If result = DialogResult.Yes Then
            Application.Exit()
        ElseIf result = DialogResult.No Then
            frmInfo.Show()
            Close()
        End If
    End If

End Sub

Private _buttons As (Button As Button, Location As Point)() = Nothing

Private Sub frmStart_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    If _buttons Is Nothing Then
        _buttons =
        {
            (btnB1, New Point(29, 32)),
            (btnB2, New Point(110, 32)),
            (btnB3, New Point(191, 32)),
            (btnB4, New Point(272, 32)),
            (btnB5, New Point(353, 32)),
            (btnB6, New Point(434, 32)),
            (btnB7, New Point(515, 32)),
            (btnB8, New Point(596, 32)),
            (btnB9, New Point(677, 32))
        }
    End If
    ResetButtons()
End Sub

Private Sub ResetButtons()
    For Each x In _buttons
        x.Button.Visible = True
        x.Button.Location = x.Location
    Next
End Sub

End Class

This Code above was from Enigmativity and FIXES a number of issues. See his comments about the Stopwatch and playing the gif. As well the game plays 70% Faster with his code


Solution

  • Trying to reproduce this NOT seeing your Timer tick code I wrote my own
    Understanding the GAME design of Breakout will help for anyone trying to follow Vectors steps need to show the gif for X amount of Seconds
    First you need to Stopwatch integrated into the Timer
    Second you need to know when to set the END time in Seconds Logic would require this happens when the BALL IntersectsWith the BRICK
    So we write a Function called Fire see code below
    NO need to have a gif for each BRICK so now we need to move our one and only gif to the correct BRICK and let it run for X Seconds We also need to make the gif Visible WHY you might ask if Enabled and Visible they run for ever It was easier to just manage Visibility
    You also need code inside the Timer Tick method to make the gif Invisible after X Seconds
    Excuse my lack of declarative variables
    pbOne = the BALL & btnB1 = BRICK & PbT = Picture Box with the gif

     Public Function Fire() As Integer
        'Set Stopwatch 5 sec in the future
        nT = CDbl(DateTime.Now.AddSeconds(5).ToString("ss"))
        Return CInt(nT)
    End Function
    
    
    Private Sub tmrMove_Tick(sender As Object, e As EventArgs) Handles tmrMove.Tick
    
        'nS is Rolling Time
        nS = CDbl(DateTime.Now.ToString("ss"))
        If nS > nT Then
            PbT.Visible = False
        End If
    
        If pbOne.Bounds.IntersectsWith(btnB1.Bounds) Then
            btnB1.BackColor = Color.Red
            btnB1.Visible = False
            Fire()
            Y = btnB1.Location.Y
            X = btnB1.Location.X
            PbT.Location = New Point(X + 20, Y)
            PbT.Visible = True
            btnB1.Location = New Point(350, -30)
            rndNUM = 8
        End If