VB.net WinForm如何寫一個分執行緒進度條
阿新 • • 發佈:2018-12-19
首先, 我們先來看一個長耗時過程
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
萌新們表示看起來很困難,我這裡不過多解釋怎麼建立分執行緒了,自己百度一下跨執行緒更新控制元件方法與原理。 我給大家說一下分執行緒窗體的呼叫方法
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
好像很簡單啊,這樣就可以在主執行緒完全卡死的情況下也能在進度條中顯示進度了,還能報告在做什麼內容,好神奇,但是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
知識點 Delegate,執行緒委託,BeginInvoke,InvokeRequired
重點解釋
- Application.Run:在當前執行緒上開始執行標準應用程式訊息迴圈,並使指定窗體可見。以該模式開啟窗體後,該執行緒窗體將持續響應訊息迴圈,該執行緒只會隨著窗體的關閉而關閉。一個執行緒只有存在一個訊息迴圈。當前執行位置將會停止在此,當制定窗體關閉後,繼續執行後面的程式碼。
PS
- 實際使用過程中,需要小夥伴們美化窗體,並新增更多的Try Catch來處理具體的異常。
- 有趣的是Devexpress提供了SplashScreenManager提供了完整的執行緒進度窗體解決方案,我們叫它飛濺窗體。基礎版使用相對簡單,但要使用自定義窗體其難度非常高,後面我開文章教大家如何使用Devexpress的控制元件(想想腦殼疼,好大的專案啊!)