delphi中timer控件的使用
很简单的只是我刚开始学,不太明白我想做label2显示当前时间procedureTaboutmeForm.Timer1Timer(Sender:TObject);begi...
很简单的
只是我刚开始学,不太明白
我想做label2显示当前时间
procedure TaboutmeForm.Timer1Timer(Sender: TObject);
begin
label2.Caption := Time $;
end;
请各位高手说一下 展开
只是我刚开始学,不太明白
我想做label2显示当前时间
procedure TaboutmeForm.Timer1Timer(Sender: TObject);
begin
label2.Caption := Time $;
end;
请各位高手说一下 展开
2个回答
展开全部
利用Delphi建立精确计数器
在Windows中的很多场合下编程(例如工业控制、游戏)中需要比较精确的记时器,本文讨论的是在Delphi下实现记时器的若干方法以及它们的精度控制问题。
在Delphi中最常用的是Timer控件,它的设置和使用都非常方便,理论上它的记时精度可以达到1ms(毫秒)。但是众所周知的,实际上Timer在记时间隔小于50ms之下是精度是十分差的。它只适用于对于精度要求不太高的场合。
这里作者要介绍的是两种利用Windows API函数实现精确记时的方法。第一中方法是利用高性能频率记数(作者本人的称呼)法。利用这种方法要使用两个API函数QueryPerformanceFrequency和QueryPerformanceCounter。QueryPerformanceFrequency函数获得高性能频率记数器的震荡频率。
调用该函数后,函数会将系统频率记数器的震荡频率(每毫秒)保存到一个LargeInteger中。不过利用该函数在几台机器上做过试验,结果都是1193180。读者朋友可以在自己的机器上试一下
QueryPerformanceCounter函数获得系统频率记数器的震荡次数,结果也保存到一个Largenteger中。
很显然,如果在计时中首先使用QueryPerformanceFrequency获得高性能频率记数器每毫秒的震荡次数,然后在计时开始时使用QueryPerformanceCounter函数获得当前系统频率记数器的震荡次数。在计时结束时再调用QueryPerformanceCounter函数获得系统频率记数器的震荡次数。将两者相减,再将结果除以频率记数器每毫秒的震荡次数,就可以获得某一事件经过的准确时间。(次数除以频率等于时间)
另外的一种精确记时器的功能是利用多媒体记时器函数(这也是作者的定义,因为这个系列的函数是在Winmm.dll中定义并且是为媒体播放服务的)。
实现多媒体记时器首先要使用timeSetEvent函数建立计时事件。该函数在Delphi中的mmsystem.pas中有定义,定义如下:
function timeSetEvent(uDelay, uResolution: UINT;
lpFunction: TFNTimeCallBack; dwUser: DWORD; uFlags: UINT): MMRESULT; stdcall
函数定义中参数uDelay定义延迟时间,以毫秒为单位,该参数相当于Timer控件的Interval属性。参数uResolution定义记时精度,如果要求尽可能高的精度,要将该参数设置为0;参数lpFunction定义了timeSetEvent函数的回调函数。该函数相当于一个定时中断处理函数,每当经过一个uDelay长度的时间间隔,该函数就会被调用,编程者可以在该函数中加入相应的处理语句。参数dwUser定义用户自定义的回调值,该值将传递给回调函数。参数uFlags定义定时类型,如果要不间断的记时,该值应设置为1。
如果函数调用成功,在系统中建立了一个多媒体记时器对象,每当经过一个uDelay时间后lpFunction指定的函数都会被调用。同时函数返回一个对象标识,如果不再需要记时器则必须要使用timeKillEvent函数删除记时器对象。
由于Windows是一个多任务的操作系统,因此基于API调用的记时器的精度都会受到其它很多因素的干扰。到底这两中记时器的精度如何,我们来使用以下的程序进行验证:
设置三种记时器(Timer控件、高性能频率记数、多媒体记时器)。将它们的定时间隔设置为10毫秒,让它们不停工作直到达到一个比较长的时间(比如60秒),这样记时器的误差会被累计下来,然后同实际经过的时间相比较,就可以得到它们的精度。
下面是具体的检测程序。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls,mmSystem;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Button1: TButton;
Button2: TButton;
Timer1: TTimer;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
actTime1,actTime2:Cardinal;
smmCount,sTimerCount,sPCount:Single;
hTimeID:Integer;
iTen:Integer;
proTimeCallBack:TFNTimeCallBack;
procedure TimeProc(uTimerID, uMessage: UINT;
dwUser, dw1, dw2: DWORD) stdcall;
procedure proEndCount;
implementation
{$R *.DFM}
//timeSetEvent的回调函数
procedure proEndCount;
begin
actTime2:=GetTickCount-actTime1;
Form1.Button2.Enabled :=False;
Form1.Button1.Enabled :=TRue;
Form1.Timer1.Enabled :=False;
smmCount:=60;
sTimerCount:=60;
spCount:=-1;
timeKillEvent(hTimeID);
end;
procedure TimeProc(uTimerID, uMessage: UINT;
dwUser, dw1, dw2: DWORD) stdcall;
begin
Form1.Edit2.Text:=FloatToStr(smmCount);
smmCount:=smmCount-0.01;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Button1.Caption :='开始倒计时';
Button2.Caption :='结束倒计时';
Button2.Enabled :=False;
Button1.Enabled :=True;
Timer1.Enabled :=False;
smmCount:=60;
sTimerCount:=60;
sPCount:=60;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
lgTick1,lgTick2,lgPer:TLargeInteger;
fTemp:Single;
begin
Button2.Enabled :=True;
Button1.Enabled :=False;
Timer1.Enabled :=True;
Timer1.Interval :=10;
proTimeCallback:=TimeProc;
hTimeID:=timeSetEvent(10,0,proTimeCallback,1,1);
actTime1:=GetTickCount;
//获得系统的高性能频率计数器在一毫秒内的震动次数
QueryPerformanceFrequency(lgPer);
fTemp:=lgPer/1000;
iTen:=Trunc(fTemp*10);
QueryPerformanceCounter(lgTick1);
lgTick2:=lgTick1;
sPCount:=60;
while sPCount>0 do begin
QueryPerformanceCounter(lgTick2);
//如果时钟震动次数超过10毫秒的次数则刷新Edit3的显示
If lgTick2 - lgTick1 > iTen Then begin
lgTick1 := lgTick2;
sPCount := sPCount - 0.01;
Edit3.Text := FloatToStr(sPCount);
在Windows中的很多场合下编程(例如工业控制、游戏)中需要比较精确的记时器,本文讨论的是在Delphi下实现记时器的若干方法以及它们的精度控制问题。
在Delphi中最常用的是Timer控件,它的设置和使用都非常方便,理论上它的记时精度可以达到1ms(毫秒)。但是众所周知的,实际上Timer在记时间隔小于50ms之下是精度是十分差的。它只适用于对于精度要求不太高的场合。
这里作者要介绍的是两种利用Windows API函数实现精确记时的方法。第一中方法是利用高性能频率记数(作者本人的称呼)法。利用这种方法要使用两个API函数QueryPerformanceFrequency和QueryPerformanceCounter。QueryPerformanceFrequency函数获得高性能频率记数器的震荡频率。
调用该函数后,函数会将系统频率记数器的震荡频率(每毫秒)保存到一个LargeInteger中。不过利用该函数在几台机器上做过试验,结果都是1193180。读者朋友可以在自己的机器上试一下
QueryPerformanceCounter函数获得系统频率记数器的震荡次数,结果也保存到一个Largenteger中。
很显然,如果在计时中首先使用QueryPerformanceFrequency获得高性能频率记数器每毫秒的震荡次数,然后在计时开始时使用QueryPerformanceCounter函数获得当前系统频率记数器的震荡次数。在计时结束时再调用QueryPerformanceCounter函数获得系统频率记数器的震荡次数。将两者相减,再将结果除以频率记数器每毫秒的震荡次数,就可以获得某一事件经过的准确时间。(次数除以频率等于时间)
另外的一种精确记时器的功能是利用多媒体记时器函数(这也是作者的定义,因为这个系列的函数是在Winmm.dll中定义并且是为媒体播放服务的)。
实现多媒体记时器首先要使用timeSetEvent函数建立计时事件。该函数在Delphi中的mmsystem.pas中有定义,定义如下:
function timeSetEvent(uDelay, uResolution: UINT;
lpFunction: TFNTimeCallBack; dwUser: DWORD; uFlags: UINT): MMRESULT; stdcall
函数定义中参数uDelay定义延迟时间,以毫秒为单位,该参数相当于Timer控件的Interval属性。参数uResolution定义记时精度,如果要求尽可能高的精度,要将该参数设置为0;参数lpFunction定义了timeSetEvent函数的回调函数。该函数相当于一个定时中断处理函数,每当经过一个uDelay长度的时间间隔,该函数就会被调用,编程者可以在该函数中加入相应的处理语句。参数dwUser定义用户自定义的回调值,该值将传递给回调函数。参数uFlags定义定时类型,如果要不间断的记时,该值应设置为1。
如果函数调用成功,在系统中建立了一个多媒体记时器对象,每当经过一个uDelay时间后lpFunction指定的函数都会被调用。同时函数返回一个对象标识,如果不再需要记时器则必须要使用timeKillEvent函数删除记时器对象。
由于Windows是一个多任务的操作系统,因此基于API调用的记时器的精度都会受到其它很多因素的干扰。到底这两中记时器的精度如何,我们来使用以下的程序进行验证:
设置三种记时器(Timer控件、高性能频率记数、多媒体记时器)。将它们的定时间隔设置为10毫秒,让它们不停工作直到达到一个比较长的时间(比如60秒),这样记时器的误差会被累计下来,然后同实际经过的时间相比较,就可以得到它们的精度。
下面是具体的检测程序。
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, ExtCtrls,mmSystem;
type
TForm1 = class(TForm)
Edit1: TEdit;
Edit2: TEdit;
Edit3: TEdit;
Button1: TButton;
Button2: TButton;
Timer1: TTimer;
procedure FormCreate(Sender: TObject);
procedure Button1Click(Sender: TObject);
procedure Timer1Timer(Sender: TObject);
procedure Button2Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
actTime1,actTime2:Cardinal;
smmCount,sTimerCount,sPCount:Single;
hTimeID:Integer;
iTen:Integer;
proTimeCallBack:TFNTimeCallBack;
procedure TimeProc(uTimerID, uMessage: UINT;
dwUser, dw1, dw2: DWORD) stdcall;
procedure proEndCount;
implementation
{$R *.DFM}
//timeSetEvent的回调函数
procedure proEndCount;
begin
actTime2:=GetTickCount-actTime1;
Form1.Button2.Enabled :=False;
Form1.Button1.Enabled :=TRue;
Form1.Timer1.Enabled :=False;
smmCount:=60;
sTimerCount:=60;
spCount:=-1;
timeKillEvent(hTimeID);
end;
procedure TimeProc(uTimerID, uMessage: UINT;
dwUser, dw1, dw2: DWORD) stdcall;
begin
Form1.Edit2.Text:=FloatToStr(smmCount);
smmCount:=smmCount-0.01;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
Button1.Caption :='开始倒计时';
Button2.Caption :='结束倒计时';
Button2.Enabled :=False;
Button1.Enabled :=True;
Timer1.Enabled :=False;
smmCount:=60;
sTimerCount:=60;
sPCount:=60;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
lgTick1,lgTick2,lgPer:TLargeInteger;
fTemp:Single;
begin
Button2.Enabled :=True;
Button1.Enabled :=False;
Timer1.Enabled :=True;
Timer1.Interval :=10;
proTimeCallback:=TimeProc;
hTimeID:=timeSetEvent(10,0,proTimeCallback,1,1);
actTime1:=GetTickCount;
//获得系统的高性能频率计数器在一毫秒内的震动次数
QueryPerformanceFrequency(lgPer);
fTemp:=lgPer/1000;
iTen:=Trunc(fTemp*10);
QueryPerformanceCounter(lgTick1);
lgTick2:=lgTick1;
sPCount:=60;
while sPCount>0 do begin
QueryPerformanceCounter(lgTick2);
//如果时钟震动次数超过10毫秒的次数则刷新Edit3的显示
If lgTick2 - lgTick1 > iTen Then begin
lgTick1 := lgTick2;
sPCount := sPCount - 0.01;
Edit3.Text := FloatToStr(sPCount);
参考资料: http://www.iyuanma.com/Book/others/jishidaquan/9/9871.html
已赞过
已踩过<
评论
收起
你对这个回答的评价是?
推荐律师服务:
若未解决您的问题,请您详细描述您的问题,通过百度律临进行免费专业咨询