2013-05-11 160 views
3

我想创建一个简单的定时器使用VB.NET秒表循环使用VB.NET

enter image description here

我想按Button1的,并开始在文本框中秒计数,这个接口。

I do not want to use the Timer Component because it does not offer high resolution.

所以,我按规格决定使用秒表类,由于其较高的分辨率。

但根据我的VB.NET代码,在我看来,整个“dotnet冒险”是不可能的。这是因为当我按下Button1时,整个窗体冻结,我不能按Button2来停止计时器。

我的代码有什么问题吗? 我应该怎么做才能具备上述功能?

在此先感谢!

 
Public Class Form1

Private enableTime As TimeSpan Private stopWatch As New Stopwatch() Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click stopWatch.Start() If stopWatch.IsHighResolution Then Do If stopWatch.ElapsedTicks.Equals(TimeSpan.TicksPerSecond) Then enableTime = enableTime + TimeSpan.FromSeconds(1) TextBox1.Text = enableTime.ToString stopWatch.Restart() End If If Not stopWatch.IsRunning Then Exit Do End If Loop End If End Sub Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click stopWatch.Stop() stopWatch.Reset() End Sub

末级

+0

即使可以找出线程和UI更新,您仍然不会获得所需的分辨率。看看你是如何检查'stopWatch.ElapsedTicks.Equals(TimeSpan.TicksPerSecond)'?这可能永远不会是真的。当你的循环正在运行时,这些滴答滴答会从你的下面滑出 - 你不会看到它们全部。即使你做了,当你重新启动计时器时,你将失去更多的分辨率。漂移是不可避免的。这不是.NET的问题,它是计算机的基本功能(至少是你使用的)。 – 2013-05-11 11:59:33

+0

在我自己的观点,我与主要概念错过分辨率以上纳秒的极少数这样的分辨率是尽可能好。但我承认我可能是错的! – Novemberland 2013-05-11 12:05:28

+0

你想要的分辨率是什么?难道你只是不会'错过'一秒钟,就像这个人在关联问题中所做的那样?或者你真的需要一堆小数位吗? – 2013-05-11 12:08:28

回答

4

Winforms中,有执行所述消息循环一个UI线程。基本上,每个事件都会被添加到消息队列中,并被处理,一个接一个的事件。当单击Button1时,将执行Button1_Click方法,直到完成后才会处理其他事件。由于您的设计需要处理Button2.Click以终止Button1.Click中的循环,因此它不会终止。

要正确实现你想要的,你必须在Button1.Click上启动秒表,并将UI更新逻辑放入您放置在窗体上的计时器的Tick事件中。

+0

+1好的答案。简洁而准确,内容翔实。我不能说得这么好。 – 2013-05-11 11:09:24

+0

@Andreas是否可以创建一个新的线程来应对所需的功能?我宁愿开始学习如何使用.NET的线程,而不必使用Timer类! – Novemberland 2013-05-11 11:22:52

+1

当然这是可能的,但在这种情况下它没有任何意义。事实上,这里没有任何线程可以实际做到。也许你认为线程可以处理UI更新,但这是不允许的,因为只有UI线程才能更新UI。如果你在另一个线程中进行UI更新,你必须在Form对象上使用Invoke,它只是将更新推送到UI线程的消息队列中(正是Timer所做的)。 @StevenDoggart谢谢,别人显然不喜欢我的回答:) – Andreas 2013-05-11 11:32:56

4

由于您正在手动添加时间范围,因此您“失去”时间:enableTime = enableTime + TimeSpan.FromSeconds(1)。秒表()本身始终准确,当您使用其Stopwatch.Elapsed属性。您只需从Timer.Tick事件更新GUI即可。基本上,计时器只是询问秒表什么是当前时间,并显示它......不需要计算。

下面将更新的第二十次,不会“漂移”,并且将不钉住CPU:

Public Class Form1 

    Private SW As New Stopwatch 
    Private WithEvents Tmr As New System.Windows.Forms.Timer 

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load 
     Tmr.Interval = 100 
    End Sub 

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click 
     SW.Start() 
     Tmr.Start() 
    End Sub 

    Private Sub Tmr_Tick(sender As Object, e As System.EventArgs) Handles Tmr.Tick 
     TextBox1.Text = SW.Elapsed.ToString 
    End Sub 

    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click 
     SW.Stop() 
     Tmr.Stop() 
     SW.Reset() 
    End Sub 

End Class 
1

一个实验表明,计时器不应该被用于定时。使用计时器定期显示秒表经过时间是很好的。

Public Class Form1 
    Private stpw As New Stopwatch 
    Private WithEvents aTimer As New System.Windows.Forms.Timer 

    Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load 
     aTimer.Interval = 100 'ten times per second 
     aTimer.Start() 'start the timer 
    End Sub 

    Private Sub timeTick(sender As Object, e As System.EventArgs) Handles aTimer.Tick 
     If stpw.IsRunning Then 
      'show that using the timer tick is not accurate for timing 
      'add the number of ms. to the timespan 
      'if the tick occurs exactly on the interval this will be accurate 

      elapsedTM = elapsedTM.Add(New TimeSpan(0, 0, 0, 0, aTimer.Interval)) 

      'show the two elapsed times 
      'as of .Net 4.0 format elapsed 
      TextBox1.Text = stpw.Elapsed.ToString("hh\:mm\:ss\.f") 
      TextBox2.Text = elapsedTM.ToString("hh\:mm\:ss\.f") 

      'show the time according to the system 
      TextBox3.Text = DateTime.Now.ToString("hh:mm:ss.f") 
      'show the time by adding the start time and the stopwatch elapsed time 
      TextBox4.Text = strt.AddMilliseconds(stpw.ElapsedMilliseconds).ToString("hh:mm:ss.f") 
     End If 
    End Sub 

    Dim strt As DateTime 
    Dim elapsedTM As TimeSpan 

    Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click 
     'start 
     If Not stpw.IsRunning Then 
      elapsedTM = New TimeSpan(0L) 
      'record the start time 
      strt = DateTime.Now 
      stpw.Start() 'start the stopwatch 
      Button2.Select() 
     End If 
    End Sub 

    Private Sub Button2_Click(sender As System.Object, e As System.EventArgs) Handles Button2.Click 
     'stop 
     stpw.Stop() 
     stpw.Reset() 
     Button1.Select() 
    End Sub 
End Class