[VB6][VBA][VB.net][自製控制項] 再談 Timer 控制項 - 時間解析度過低的解決方法(三)自製「使用者制項」
- 前文介紹了VB.net 用 Stopwatch 提升Timer 解析度的方法,在最後提到了做成獨立的控制項再封裝成 dll 來使用,現在就做它一下。
-
下圖是專案完成後,實際拿來測試時的擷圖:
- 我們一步一步進行:
準備活動:
-
為使產品能有專業化的外觀(只是外觀啦)決定先做一個 Icon,當它被放在工具箱時會有一張像樣的臉孔。
- 最好是包含(16x16、32x32)二種 Format 的 .ico 檔,我用(Axialis IconWorkshop)這套工具。
-
手邊如沒有 Icon 工具可用其他繪圖工具或小畫家也可以(圖形格式 ico、png、bmp 等都可)。
-
想一下這個控制項和 VB.net 原來的 Timer 要有哪些不同處,我的想法是這幾項:
- 時間的解析度要更高,最好是能辨識到 0.1ms 以上。
- 功能也要多一些,要能提供二組計時週期事件(大週期中含有小週期)。
- 要有只執行一個計時週期的功能,時間到了就自動 Disabled 不再繼續觸發事件。
- 要能輸出方波,並且可調整高低波數比。例如 3:7 的波形就連續3個週期高值(1),再接著7個週期的低值(0)。
- 既然是用 Stopwatch 為主角,那就再加送一個傳回 CPU clock 速度的屬性吧。
- 準備一段清淨的時間再加一顆清醒的腦袋(這個很重要)。
發展活動:
-
建立專案環境:
- 準備一個空資料夾命名為「我的專案資料夾」,然後執行 Visual Studio .net 2010(用 2005、2008 應該也行)。
- [檔案][新增專案]選擇[類別庫專案]輸入名稱為 myControl → 按下確定。
- 在方案總管的根節點右鍵擇[加入][元件][元件類別]輸入名稱為 myTimer → 按下新增。
- [檔案][全部儲存]瀏覽到[我的專案資料夾]DblClick 選擇它再按[選擇資料夾]然後[儲存]。
- 在方案中加入一個測試專案[檔案][加入][新增專案]選擇[Windows Form 應用程式專案]輸入名稱為 myTimer_測試專案→ 按下確定。
- 在方案總管的 myTimer_測試專案 上面按右鍵擇[設為啟動專案]。
- [檔案][全部儲存](這次不會再有提示框了)。
-
程式碼撰寫:
-
先做一次[建置][重建專案]這時你的專案資料夾會長得像下圖(工具箱會出現 myControl 標籤,裡面會有個齒輪狀的控制項):
- 在方案總管的 myControl 上面按右鍵擇[在檔案總管開啟]然後把你的圖示檔複製進去,重新整理後就會看到它了。
- 在圖示檔名身上按右鍵選擇[加入至專案]後再於屬性欄設為[內嵌資源]如下圖(一)。
-
編輯 myTimer.vb 先加入下程式碼,然後[重建專案]一次 。
Imports System.Diagnostics Imports System.ComponentModel Imports System.Drawing Imports System.Windows.Forms <DefaultEventAttribute("Tick"), System.Drawing.ToolboxBitmap(GetType(myTimer), "__Ku_Timer.ico")> _ Public Class myTimer #Region "---宣告---" Private 第一計時器 As Stopwatch '---第一個計時器控管工作總時間。 Private 第二計時器 As Stopwatch '---第二個計時器控管計時小秒。 Private 小秒週期 As Single = Stopwatch.Frequency / 10000 '---因為要產生 t/10 的事件所以定 0.1ms 為小秒週期。 Private new_工作時間毫秒數 As Integer = 0 '---可決定是否產生 TimeUp() 事件,預設0表示不限時。 Private new_閃爍訊號_Hi_count = 5 '---輸出閃爍訊號的 Hi_Lo 週期長度比,預設5為1:1(高5_低5) Private new_Enabled As Boolean '---啟動/停止。 Private new_Interval As Single = 100 '---高解析度 Timer 預設週期為 0.1秒。 Public Enum em方波形狀 '---決定方波形狀的列舉常數--- [高1_低9] = 1 [高2_低8] = 2 [高3_低7] = 3 [高4_低6] = 4 [高5_低5] = 5 [高6_低4] = 6 [高7_低3] = 7 [高8_低2] = 8 [高9_低1] = 9 End Enum Public Enum em方波訊號值 '---決定方波訊號 High、Low 值的列舉常數--- [Low] = 0 [High] = 1 End Enum #End Region #Region "---事件---" Event Flash(ByVal sender As Object, ByVal e As EventArgs, ByVal V As em方波訊號值) Event Hires_Tick_10x(ByVal sender As Object, ByVal e As EventArgs, ByVal T As Single) Event Tick(ByVal sender As Object, ByVal e As EventArgs, ByVal T As Single) Event TimeUp(ByVal sender As Object, ByVal e As EventArgs) #End Region End Class
-
再[重建專案]一次工具箱就有它的身影了,下圖可參考。
-
繼續加入屬性和方法的程式碼:
#Region "---屬性---" <Description("當下電腦的 CPU 運算速度"), Browsable(True), Category("其他")> _ Public ReadOnly Property CPU_GHz() As String Get Return Format(Stopwatch.Frequency / 10 ^ 9 * 1024, "##.##0 GHz") End Get End Property <Description("限定工作時間毫秒數"), Browsable(True), Category("行為")> _ Public Property 工作時間毫秒數設定() As Integer Get Return new_工作時間毫秒數 End Get Set(ByVal value As Integer) new_工作時間毫秒數 = value End Set End Property <Description("啟動/停止 Timer"), Browsable(True), Category("行為")> _ Public Property Enabled() As Boolean Get Return new_Enabled End Get Set(ByVal value As Boolean) new_Enabled = value If DesignMode Then Exit Property If new_Enabled Then 第一計時器 = New Stopwatch 第一計時器.Restart() 計時開始() Else 第一計時器 = Nothing End If End Set End Property <Description("事件週期長度(ms)"), Browsable(True), Category("行為")> _ Public Property Interval() As Single Get Return new_Interval End Get Set(ByVal value As Single) If value < 0 Then value = 0 new_Interval = Math.Round(value, 3) End Set End Property <Description("設定輸出閃爍波(方波)的週期樣式"), Browsable(True), Category("行為")> _ Public Property 方波形狀() As em方波形狀 Get Return new_閃爍訊號_Hi_count End Get Set(ByVal value As em方波形狀) new_閃爍訊號_Hi_count = value End Set End Property #End Region #Region "---方法---" Private Sub 計時開始() Static tCounts As Integer Dim 小秒週期數 As Integer '---把一個 Interval 週期均分為10 等分決定定方波形狀--- 第二計時器 = New Stopwatch '---產生小秒時脈基準--- 第二計時器.Restart() '---重新啟動小秒計時--- Do While (Not DesignMode AndAlso new_Enabled AndAlso new_Interval > 0 AndAlso Container IsNot Nothing) tCounts = 第二計時器.ElapsedTicks If tCounts >= new_Interval * 小秒週期 Then 第二計時器.Restart() '---小秒重新置0--- 小秒週期數 += 1 : If 小秒週期數 = 10 Then 小秒週期數 = 0 '---統計進行了幾個小秒--- If 小秒週期數 >= 0 Then If 事件綜合處理(小秒週期數, tCounts) Then Exit Do '---傳回 True 表示時間到 End If End If Application.DoEvents() Loop End Sub Private Function 事件綜合處理(ByVal 小秒週期數 As Integer, ByVal tCounts As Integer) As Boolean '---根據小秒數決定發出哪些事件--- RaiseEvent Hires_Tick_10x(Me, New System.EventArgs, tCounts / Stopwatch.Frequency) If 小秒週期數 = 0 Then RaiseEvent Tick(Me, New System.EventArgs, tCounts / Stopwatch.Frequency * 10) RaiseEvent Flash(Me, New System.EventArgs, em方波訊號值.Low) '---送出方波 Low --- ElseIf 小秒週期數 = new_閃爍訊號_Hi_count Then ' RaiseEvent Flash(Me, New System.EventArgs, em方波訊號值.High) '---送出方波 High --- End If '---檢查是否 Time Up--- If new_工作時間毫秒數 <> 0 Then If 第一計時器.ElapsedMilliseconds >= new_工作時間毫秒數 Then new_Enabled = False RaiseEvent TimeUp(Me, New System.EventArgs) 小秒週期數 = 0 Return True End If End If Return False End Function #End Region
-
先做一次[建置][重建專案]這時你的專案資料夾會長得像下圖(工具箱會出現 myControl 標籤,裡面會有個齒輪狀的控制項):
測試:
-
在測試專案的 Form1 加入程式碼,然後按[F5]執行。
Public Class Form1 Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load Me.Text = MyTimer1.CPU_GHz End Sub Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click With MyTimer1 .工作時間毫秒數設定 = 30 '---執行 30ms 後自動停止. .Interval = 10 '---設為 10ms 可解析至 1ms .Enabled = True End With End Sub Private Sub Tick(ByVal sender As Object, ByVal e As System.EventArgs, ByVal T As Single) Handles MyTimer1.Tick Debug.Print(Format(T, "#0.#####0 s")) End Sub Private Sub Flash(ByVal sender As Object, ByVal e As System.EventArgs, ByVal V As myControl.myTimer.em方波訊號值) Handles MyTimer1.Flash Debug.Print(Format(vbTab & V.ToString)) End Sub Private Sub Hires_Tick_10x(ByVal sender As Object, ByVal e As System.EventArgs, ByVal T As Single) Handles MyTimer1.Hires_Tick_10x Debug.Print(vbTab & vbTab & Format(T, "#0.#####0 s")) End Sub End Class
-
把輸出組件的 myControl.dll 直接加入到工具箱,就可以看到它的外形變美了。
結語:
- 這篇貼文只在提示建立[使用者控制項]的過程。
- 因為接觸 VB.net 時間不長(過去都在玩 VB6 從今年四月才開始學 VB.net)裡面所用的方法和程式碼還很幼稚園級,所以參考就好。
-
專案包下載 myControl_案資料夾.rar