首先, 我们先来看一个长耗时过程
Private Sub ValueTest()
For i As Integer = 0 To 100
ProgressBar1.Value = i
Threading.Thread.Sleep(1000)
Next
End Sub
我们会发现,在100时间内,窗体无法被移动,进度条也不会移动(win10的UI可以移动,但任然看起来很卡),等循环完毕后进度条突然就满了。
懂UI窗体运行原理的都知道,程序的主线程不仅仅要处理我们写的代码,还要刷新UI的界面。当在处理长耗时过程时,UI界面也会被“锁死”,直到过程被执行完毕。
有些懂线程委托的小朋友就要说了,用分线程委托嘛,例如这样:
Private Sub ValueTest_Thread()
For i As Integer = 0 To 100
ChangePBValue(i, ProgressBar1)
Threading.Thread.Sleep(1000)
Next
End Sub
Private Sub ChangePBValue(_Value As Integer, ByRef _PB As ProgressBar)
If _PB.InvokeRequired = True Then
_PB.BeginInvoke(New D_ChangePBValue(AddressOf ChangePBValue), _Value, _PB)
Else
_PB.Value = _Value
End If
End Sub
Private Delegate Sub D_ChangePBValue(_Value As Integer, ByRef _PB As ProgressBar)
Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
Dim NT As New Threading.Thread(AddressOf ValueTest_Thread)
NT.Start()
End Sub
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
萌新们表示看起来很困难,我这里不过多解释怎么创建分线程了,自己百度一下跨线程更新控件方法与原理。
我给大家说一下分线程窗体的调用方法
Private Sub ValueTest_ThreadForm()
ThreadPBManger.Start("我想表达点什么呢???")
For i As Integer = 0 To 100
ThreadPBManger.SetValue(i)
Threading.Thread.Sleep(100)
Next
ThreadPBManger.Stop()
End Sub
- 7
- 8
好像很简单啊,这样就可以在主线程完全卡死的情况下也能在进度条中显示进度了,还能报告在做什么内容,好神奇,但是ThreadPBManger是什么鬼?
Public Module ThreadPBManger
Dim NF_PB As F_PB
Public Sub Start(ShowStr As String)
Dim NT As New Threading.Thread(AddressOf Start_thread)
NT.Start(ShowStr)
End Sub
Private Sub Start_thread(ShowStr As String)
NF_PB = New F_PB
NF_PB.Text = ShowStr
Application.Run(NF_PB)
End Sub
Public Sub SetValue(Value As Integer)
If IsNothing(NF_PB) Then Return
If NF_PB.IsDisposed Then Return
ChangePBValue(Value, NF_PB.ProgressBar1)
End Sub
Private Delegate Sub D_Stop()
Public Sub [Stop]()
If IsNothing(NF_PB) Then Return
If NF_PB.IsDisposed Then Return
If NF_PB.InvokeRequired Then
NF_PB.Invoke(New D_Stop(AddressOf [Stop]))
Else
NF_PB.Dispose()
End If
End Sub
#Region "委托更新PB"
Public Sub ChangePBValue(_Value As Integer, ByRef _PB As ProgressBar)
If _PB.InvokeRequired = True Then
_PB.BeginInvoke(New D_ChangePBValue(AddressOf ChangePBValue), _Value, _PB)
Else
_PB.Value = _Value
End If
End Sub
Private Delegate Sub D_ChangePBValue(_Value As Integer, ByRef _PB As ProgressBar)
#End Region
End Module
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
源码位置 https://download.csdn.net/download/meiren777/10762052
知识点
Delegate,线程委托,BeginInvoke,InvokeRequired
重点解释
Application.Run:在当前线程上开始运行标准应用程序消息循环,并使指定窗体可见。以该模式打开窗体后,该线程窗体将持续响应消息循环,该线程只会随着窗体的关闭而关闭。一个线程只有存在一个消息循环。当前执行位置将会停止在此,当制定窗体关闭后,继续执行后面的代码。
PS
实际使用过程中,需要小伙伴们美化窗体,并添加vb.net教程更多的Try Catch来处理具体的异常。
有趣的是Devexpress提供了SplashScreenManager提供了完整的线程进度窗体解决方案,我们叫它飞溅窗体。基础版使用相对简单,但要使用自定义窗体其难度非常高,后面我开文章教大家如何使用Devexpress的控件(想想脑壳疼,好大的项目啊!)