Я хотел бы показать GIF внутри Picture Box в течение 2 секунд в отдельном потоке от основного потока. Я запускаю таймер, который перемещает Picture Box с изображением в основном потоке.
Чтобы проверить, я создал Picture Box и добавил то же изображение. Я запускаю фоновый поток нажатием кнопки. Очевидная ОШИБКА или проблема заключается в том, что предполагаемый фоновый поток замедляет основной поток.
Создание и реализация потоков предлагает два варианта: BackgroundWorker и Task.Run.
Я просмотрел эту статью журнала Code Magazine, в которой было предложено гораздо больше вариантов, чем я понимаю: Статья журнала Code
Также просмотрел эту статью. Не удалось преобразовать код С# в VB. ДА. Я использовал преобразователь кода: Стивен Клири
Мой код размещен ниже для фоновой темы. Нет необходимости публиковать код таймера Tick.
Вопрос, что я упустил или что я делаю неправильно ИЛИ это просто невозможно?
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
Ответ на вопрос был добавлен Craig и ответил 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
Конец класса
Приведенный выше код был получен от Enigmativity и ИСПРАВЛЯЕТ ряд проблем. См. его комментарии о секундомере и воспроизведении гифки. Кроме того, с его кодом игра работает на 70 % быстрее
Thread.Abort()
опасно. Его следует вызывать только тогда, когда вы пытаетесь принудительно закрыть приложение. Это может оставить среду выполнения в неопределенном состоянии и повлиять на все оставшиеся потоки и код, который вы выполняете. Вы должны позволить потокам заканчиваться естественным образом. - person Enigmativity   schedule 15.09.2020Dim myThread ...
вmyThread.Start()
вне метода и запустите поток откуда-нибудь. Поместите остальную часть кода в циклWhile true
и добавьте, например,Thread.Sleep(50)
. УдалитеmyThread.Abort()
и простоReturn
. Вы должны проверить, удален ли ваш элемент управления, потому что, если вы тем временем закроете форму, произойдет крах. - person Jimi   schedule 15.09.2020Task.Delay()
вместоThread.Sleep()
иBeginInvoke()
вместоInvokeRequired/Invoke()
. ПередайтеCancellationToken
(изCancellationTokenSource
), если вы хотитеCancel()
выполнить задание до его завершения. Все 3 метода теперь асинхронны (ни один из них не будет блокировать поток пользовательского интерфейса. Даже стандартный таймер, поскольку вы просто перемещаете элемент управления). - person Jimi   schedule 15.09.2020await Task.Delay(milliseconds)
для создания задачи, которая продолжается после указанного времени. Используя свой поток (измененный, как описано), простоReturn
послеThread.Sleep(9000)
, чтобы закончить поток. Я не знаю, о чем идет речь в GIF, так как у вас здесь нет GIF. Если вам нужна помощь по этому поводу, вам придется объяснить, чего вы пытаетесь достичь, намного лучше. Если ваш PictureBox (я так думаю) содержит анимированный GIF, вам нечего делать. ImageAnimator в любом случае будет анимировать GIF. - person Jimi   schedule 15.09.2020