You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在新线程中创建Timer解决PictureBox扫线卡顿问题

解决PictureBox扫线鼠标移动卡顿问题

原WinForms Timer运行在UI线程,当鼠标在PictureBox内移动时,UI线程被鼠标消息占用,导致Timer的Tick事件延迟,扫线出现卡顿。以下是两种基于后台线程的解决方案:

方案一:使用System.Threading.Timer

该Timer基于线程池运行,不会阻塞UI线程,适合定时更新逻辑。

完整代码示例

Private lineX As Integer = 0
Private updateTimer As System.Threading.Timer
Private lockObj As New Object() ' 保证lineX的线程安全访问

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    ' 初始化Timer,每隔16ms触发一次(约60帧刷新率),立即启动
    updateTimer = New System.Threading.Timer(AddressOf TimerCallback, Nothing, 0, 16)
End Sub

Private Sub TimerCallback(state As Object)
    ' 线程安全更新lineX
    SyncLock lockObj
        lineX += 5
        If lineX > PictureBox1.Width Then
            lineX = 0
        End If
    End SyncLock

    ' 跨线程刷新UI,必须通过Invoke确保在UI线程执行
    If PictureBox1.InvokeRequired Then
        PictureBox1.Invoke(Sub() PictureBox1.Invalidate())
    Else
        PictureBox1.Invalidate()
    End If
End Sub

Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint
    SyncLock lockObj
        e.Graphics.DrawLine(Pens.Black, New Point(lineX, 0), New Point(lineX, PictureBox1.Height))
    End SyncLock
End Sub

Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
    ' 释放Timer资源
    updateTimer?.Dispose()
End Sub

关键说明

  • System.Threading.Timer的回调在线程池线程执行,不会被UI线程的鼠标操作阻塞
  • SyncLock用于保证lineX在多线程访问时的安全性
  • 使用Invoke将UI刷新操作切换回UI线程,符合WinForms控件的线程安全要求

方案二:使用BackgroundWorker

BackgroundWorker封装了线程操作,自带进度更新的线程安全机制,适合简单的后台循环任务。

完整代码示例

Private lineX As Integer = 0
Private bgWorker As New BackgroundWorker()
Private lockObj As New Object()

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
    bgWorker.WorkerReportsProgress = True
    bgWorker.WorkerSupportsCancellation = True
    AddHandler bgWorker.DoWork, AddressOf BgWorker_DoWork
    AddHandler bgWorker.ProgressChanged, AddressOf BgWorker_ProgressChanged
    bgWorker.RunWorkerAsync()
End Sub

Private Sub BgWorker_DoWork(sender As Object, e As DoWorkEventArgs)
    Dim worker As BackgroundWorker = CType(sender, BackgroundWorker)
    ' 循环更新直到收到取消信号
    While Not worker.CancellationPending
        SyncLock lockObj
            lineX += 5
            If lineX > PictureBox1.Width Then
                lineX = 0
            End If
        End SyncLock
        ' 通知UI线程刷新
        worker.ReportProgress(0)
        ' 控制刷新间隔,约60帧
        System.Threading.Thread.Sleep(16)
    End While
End Sub

Private Sub BgWorker_ProgressChanged(sender As Object, e As ProgressChangedEventArgs)
    ' ProgressChanged事件自动在UI线程执行,无需额外Invoke
    PictureBox1.Invalidate()
End Sub

Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint
    SyncLock lockObj
        e.Graphics.DrawLine(Pens.Black, New Point(lineX, 0), New Point(lineX, PictureBox1.Height))
    End SyncLock
End Sub

Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
    ' 关闭时取消后台任务
    If bgWorker.IsBusy Then
        bgWorker.CancelAsync()
    End If
End Sub

关键说明

  • DoWork事件在后台线程执行更新逻辑,不会占用UI线程
  • ProgressChanged事件自动切换到UI线程,直接调用Invalidate()即可刷新
  • 支持通过CancelAsync()安全终止后台任务

内容的提问来源于stack exchange,提问作者user1377723

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 03:57:37