用VB.NET实现秒表回路

用VB.NET实现秒表回路,vb.net,time,stopwatch,Vb.net,Time,Stopwatch,我想用VB.NET创建一个简单的计时器 我想按下按钮1并开始计算文本框中的秒数 因此,我决定使用stopWatch类,因为根据规范,它的分辨率很高 但根据我下面的VB.NET代码,我觉得整个“网络冒险”是不可能的。这是因为当我按下按钮1时,整个表单都冻结了,我无法按下按钮2来停止计时器 我的代码有什么问题吗? 我应该怎么做才能拥有上述功能 提前谢谢 在WinForms中,有一个UI线程执行消息循环。基本上,每个事件都被添加到消息队列中,消息队列一个接一个地被处理。单击Button1时,将执

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

我想按下按钮1并开始计算文本框中的秒数

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

但根据我下面的VB.NET代码,我觉得整个“网络冒险”是不可能的。这是因为当我按下按钮1时,整个表单都冻结了,我无法按下按钮2来停止计时器

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

提前谢谢


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

要正确实现您想要的功能,您必须在
按钮1上启动秒表。单击
并将UI更新逻辑放入放置在表单上的计时器的
勾选事件中。

您正在“损失”时间,因为您正在手动添加到时间跨度:
启用时间=启用时间+时间跨度。FromSeconds(1)
。使用秒表的
Stopwatch.appeased
属性时,秒表()本身总是准确的。您需要做的就是从
计时器更新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

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

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

+回答得好。简洁而准确,信息丰富。我不可能把它放得这么好。@Andreas有可能创建一个新线程来处理所需的功能吗?我更喜欢开始学习如何在.NET中使用线程,而不是使用计时器类!当然这是可能的,但在这种情况下没有任何意义。事实上,线程在这里实际上做不了什么。也许您认为线程可以处理UI更新,但这是不允许的,因为只有UI线程可以进行UI更新。如果在另一个线程中进行UI更新,则必须在表单对象上使用Invoke,这实际上只是将更新推送到UI线程的消息队列(正是计时器所做的)@Stevendogart谢谢,其他人显然不喜欢我的答案:)@Andreas有没有可能用代码来说明你自己的观点,以便更好地获取你的建议?定时器将采用上述功能的哪一部分?提前谢谢@Novenberland:你一直反对使用
定时器,但没有任何好的理由这么做。如果你唯一的反对意见是相关问题,那么我认为这是错的。如果您只关心实际计时的准确性,那么使用
秒表
进行测量和
计时器
进行更新就可以了。即使您能够了解线程和UI更新,您仍然无法获得所需的分辨率。查看如何检查秒表.ElapsedTicks.Equals(TimeSpan.TicksPerSecond)
?这可能永远不会是真的。当你的循环运行时,这些滴答声会从你的下方滑出——你不会看到所有的滴答声。即使你这样做了,当你重新启动计时器时,你也会失去更多的分辨率。随波逐流是不可避免的。这不是.NET的问题,它是计算机的一个基本特性(至少是你正在使用的那些)。在我看来,我在上面主要概念中忽略的分辨率是一个极小的纳秒数,因此分辨率尽可能好。但我承认我可能错了!你想要的决议的要点是什么?只是为了让你不会像链接问题中的人那样“错过”一秒钟?或者你真的需要一些小数位吗?我希望它是一个商业项目,所以它必须有可能的最佳分辨率。你的商业产品可以接受固定CPU吗?即使使用后台线程,您的解决方案也将始终运行,这意味着处理器将永远无法休息(如果适用,电池寿命将受到影响)。在这种情况下,这可能没问题,但我只是想确保你意识到了这一点。
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