【问题标题】:StopWatch Loop using VB.NET使用 VB.NET 的秒表循环
【发布时间】:2013-05-05 23:13:04
【问题描述】:

我想用 VB.NET 用这个接口创建一个简单的计时器

我想按下 Button1 并开始在文本框中计算秒数。

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

因此,我决定使用 stopWatch 类,因为它根据规范具有高分辨率。

但根据我下面的 VB.NET 代码,在我看来,整个“dotnet 冒险”是不可能的。那是因为当我按下 Button1 时,它会冻结整个表单,我无法按下 Button2 来停止计时器。

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

提前致谢!

公开课形式1 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

结束类

【问题讨论】:

  • 即使您能弄清楚线程和 UI 更新,您仍然无法获得您想要的分辨率。看看你是如何检查stopWatch.ElapsedTicks.Equals(TimeSpan.TicksPerSecond) 的?那可能永远不会是真的。当您的循环运行时,这些刻度会从您下方滑出——您不会全部看到它们。即使你这样做了,当你重新启动计时器时,你也会失去更多的分辨率。漂移是不可避免的。这不是 .NET 的问题,它是计算机的基本功能(至少是您正在使用的计算机)。
  • 在我自己的观点中,我在上面的主要概念中错过的分辨率是很小的纳秒数,因此分辨率尽可能好。但我承认我可能错了!
  • 你想要的分辨率有什么意义?只是为了让您不会像链接问题中的人那样“错过”一秒钟吗?还是你真的需要一堆小数位?
  • 我希望它是一个商业项目,所以它必须有尽可能好的分辨率。
  • 你的商业产品可以接受CPU吗?即使使用后台线程,您的解决方案也将始终运行,这意味着处理器永远不会休息(如果适用,电池寿命也会受到影响)。在这种情况下可能没问题,但只是想确保您意识到这一点。

标签: vb.net time stopwatch


【解决方案1】:

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

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

【讨论】:

  • +1 不错的答案。简洁而准确和信息丰富。我不能说得这么好。
  • @Andreas 是否可以创建一个新线程来处理所需的功能?我更愿意开始学习如何在 .NET 中使用线程,而不是必须使用 Timer Class!
  • 当然可以,但在这种情况下没有任何意义。事实上,线程实际上无法在这里做任何事情。也许你认为线程可以处理 UI 更新,但这是不允许的,因为只有 UI 线程才能进行 UI 更新。如果您在另一个线程中进行 UI 更新,则必须在 Form Object 上使用 Invoke,这实际上只是将更新推送到 UI 线程的消息队列(正是计时器所做的)。 @StevenDoggart 谢谢,其他人显然不喜欢我的回答:)
  • @Andreas 是否可以用代码说明您自己的观点,以便更好地获取您的建议? Timer 将包含上述哪些功能?提前致谢!
  • @Novemberland:您一直表示反对使用Timer,但没有任何充分的理由这样做。如果您唯一的反对意见是链接的问题,那么我认为它放错了地方。如果你只关心实际计时有多准确,那么使用Stopwatch 测量和Timer 更新就可以了。
【解决方案2】:

您正在“浪费”时间,因为您手动添加时间跨度:enableTime = enableTime + TimeSpan.FromSeconds(1)。当您使用其Stopwatch.Elapsed 属性时,Stopwatch() 本身始终是准确的。您需要做的就是从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

【讨论】:

    【解决方案3】:

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

    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
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-04-21
      • 1970-01-01
      • 2022-12-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多