delphi - Delphi TTimer 在 Win 10 中提供不寻常的结果
问题描述
我有一个应用程序,允许我的用户打开和关闭计时器来跟踪他们在某项任务上花费的时间。计时器运行一个时钟,用于向用户显示经过的时间,就像秒表一样。
下面的代码已经像我认为的那样工作了几年。但是,当应用在 Win 10 上运行时,有时“时间”速率会在一个会话期间加快 2 或 3 倍。如果用户重新启动应用程序,它可能会以正常速度运行。
赢得 10 德尔福 10.3
procedure TfmTimeCard.btnTimerClick(Sender: TObject);
begin
if btnTimer.Caption = 'Start &Timer' then
begin
btnTimer.Down := True;
btnTimer.Caption := 'Stop &Timer';
pnlTimer.Color := clPurple;
btnResume.Enabled := True;
btnAssign.Enabled := False;
Timer1.Enabled := true;
UpdateTimer.Enabled := True;
ElapsedTime := ElapsedTime;
//btnPostRecord.Enabled := False;
btnCancel.Enabled := False;
btnDeleteTimeCard.Enabled := False;
end
else
begin
btnTimer.Down := False;
btnTimer.Caption := 'Start &Timer';
pnlTimer.ParentColor := True;
btnResume.Enabled := False;
btnAssign.Enabled := True;
pnlTimer.Color := clMoneyGreen;
end;
end;
procedure TfmTimeCard.Timer1Timer(Sender: TObject);
begin
if btnTimer.Caption = 'Stop &Timer' then
begin
ElapsedTime := ElapsedTime + 0.0000115740;
cxClock1.time := ElapsedTime;
cxTimeEditTimer.Time := ElapsedTime;
end;
end;
解决方案
这是使用TTimer
. TTimer
不是实时计时器,甚至不是精确计时器。它基于WM_TIMER
窗口消息,即
低优先级消息。
GetMessage
和PeekMessage
函数仅在线程的消息队列中没有其他更高优先级的消息时才发布此消息。
不要根据触发事件ElapsedTime
的频率来计算您的值。开始时跟踪当前时间,然后在最终生成事件时从下一个当前时间中减去该值。这会给你一个更真实的经过时间。TTimer
OnTimer
TTimer
OnTimer
尝试更多类似的东西:
uses
..., System.DateUtils;
private
StartTime: TDateTime;
ElapsedSecs: Int64;
procedure TfmTimeCard.btnTimerClick(Sender: TObject);
begin
if btnTimer.Tag = 0 then
begin
btnTimer.Tag := 1;
...
ElapsedSecs := 0;
StartTime := Now;
Timer1.Enabled := true;
...
end
else
begin
btnTimer.Tag := 0;
...
ElapsedSecs := SecondsBetween(Now, StartTime);
Timer1.Enabled := false;
...
end;
end;
procedure TfmTimeCard.Timer1Timer(Sender: TObject);
begin
if btnTimer.Tag = 1 then
begin
ElapsedSecs := SecondsBetween(Now, StartTime);
// use ElapsedSecs as needed ...
end;
end;
或者:
uses
..., Winapi.Windows;
private
StartTime: DWORD;
ElapsedSecs: Integer;
procedure TfmTimeCard.btnTimerClick(Sender: TObject);
begin
if btnTimer.Tag = 0 then
begin
btnTimer.Tag := 1;
...
ElapsedSecs := 0;
StartTime := GetTickCount;
Timer1.Enabled := true;
...
end
else
begin
btnTimer.Tag := 0;
...
ElapsedSecs := (GetTickCount - StartTime) div 1000;
Timer1.Enabled := false;
...
end;
end;
procedure TfmTimeCard.Timer1Timer(Sender: TObject);
begin
if btnTimer.Tag = 1 then
begin
ElapsedSecs := (GetTickCount - StartTime) div 1000;
// use ElapsedSecs as needed ...
end;
end;
或者:
uses
..., System.Diagnostics;
private
SW: TStopwatch;
ElapsedSecs: Integer;
procedure TfmTimeCard.btnTimerClick(Sender: TObject);
begin
if not SW.IsRunning then
begin
...
ElapsedSecs := 0;
SW := TStopWatch.Start;
Timer1.Enabled := true;
...
end
else
begin
...
SW.Stop;
ElapsedSecs := Trunc(SW.Elapsed.TotalSeconds);
Timer1.Enabled := false;
...
end;
end;
procedure TfmTimeCard.Timer1Timer(Sender: TObject);
begin
if SW.IsRunning then
begin
ElapsedSecs := Trunc(SW.Elapsed.TotalSeconds);
// use ElapsedSecs as needed ...
end;
end;
推荐阅读
- r - Linux服务器上的R memoise
- c# - StructureMap 2.5.3 in .Net 4.5.2 延迟加载问题
- scala - 是否可以测试一个值的类是否属于内部类类型
- javascript - Electron 不会从 JSON 打开文件
- sql - SQL 多个 where 子句
- encoding - 如何在 NetLogo 中让乌龟成倍增长?
- android - 使用 DialogFragment 和导航库时将对话框显示为全屏或对话框
- html - Table Html 5 th td 问题
- algorithm - 可以使用 O(1) 或 O(log n) 来计算元素数量吗?
- android - 当应用程序在 Android 上中断时,我的“共享项目”中的课程会发生什么情况?