2013-05-11 3 views
3

Я хочу, чтобы создать простой таймер с этим интерфейсом, используя VB.NETСекундомер Loop с использованием 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

Вы по-прежнему не хотите получать требуемое разрешение, даже если вы можете выяснить, сколько потоков и обновления пользовательского интерфейса. Посмотрите, как вы проверяете 'stopWatch.ElapsedTicks.Equals (TimeSpan.TicksPerSecond)'? Возможно, это никогда не будет правдой. Пока ваша петля работает, эти тики выскользнут из-под вас - вы их не увидите. И даже если вы это сделаете, вы потеряете больше разрешения при перезапуске таймера. Дрифт неизбежен. Это не проблема с .NET, это базовая функция компьютеров (по крайней мере, тех, которые вы используете). –

+0

В моей собственной точке зрения резолюция, которую я пропустил, с основной концепцией выше, представляет собой крошечное количество наносекунд, поэтому разрешение как можно лучше. Но я признаю, что я ошибаюсь! – Novemberland

+0

Какой смысл разрешения вы хотите? Разве это не значит, что вы не пропустите секунду, как это делал человек в связанном вопросе? Или вам действительно нужна куча десятичных знаков? –

ответ

4

В WinForms, есть один поток пользовательского интерфейса выполняет цикл обработки сообщений. В принципе, каждое событие добавляется в очередь сообщений, которая обрабатывается, одно событие за другим. При нажатии Button1 выполняется метод Button1_Click, и никакое другое событие не будет обработано до его завершения. Поскольку для вашего проекта требуется обработать Button2.Click, чтобы завершить цикл в Button1.Click, он никогда не завершится.

Чтобы правильно реализовать то, что вы хотите, вам нужно запустить секундомер на Button1.Click и поместить логику обновления пользовательского интерфейса в событие Tick таймера, который вы поместите в форму.

+0

+1 Хороший ответ. Краткая, но точная и информативная. Я не мог бы сказать так хорошо. –

+0

@Andreas Возможно ли создать новый поток, который справится с желаемой функциональностью? Я предпочитаю начинать изучать, как использовать потоки с .NET, чем использовать Timer Class! – Novemberland

+1

Конечно, это возможно, но в этом случае это не имеет никакого смысла. На самом деле, ничто не может реально сделать здесь нить. Возможно, вы подумали, что поток может обрабатывать обновления пользовательского интерфейса, но это не разрешено, поскольку только поток пользовательского интерфейса может создавать обновления пользовательского интерфейса. Если вы выполняете обновления пользовательского интерфейса в другом потоке, вы должны использовать Invoke для объекта формы, который действительно просто подталкивает обновление к очереди сообщений в потоке пользовательского интерфейса (точно, что делает таймер). @StevenDoggart спасибо, кому-то, очевидно, не понравился мой ответ :) – Andreas

4

Вы теряете время, потому что вручную добавляете к временному интервалу: enableTime = enableTime + TimeSpan.FromSeconds(1). Секундомер() сам всегда точен, когда вы используете его свойство Stopwatch.Elapsed. Все, что вам нужно сделать, это обновить графический интерфейс от события Timer.Tick. В основном таймер просто спрашивает секундомер, что такое текущее время и отображает его ... никаких расчетов не требуется.

Ниже будет обновлять десять раз в секунду, не будет «дрейф», и не будет привязывать процессор:

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