我需要制作一个简单的闹钟应用程序,它不会播放声音,而是将文件上传到ftp(后者弄明白了)。 在执行线程时,计时器被证明是无效的。
这是我到目前为止所得到的:
var
ttime : tDateTime;
timerstr : string;
timealarm : string;
aThread : TMyThread;
begin
aThread := tMyThread.Create(false);
ttime := Now;
timestr := FormatDateTime('hh:nn:ss', ttime);
timealarm := '09:30:30';
if timestr = timealarm then
aThread.Resume; //The thread will execute once and terminate;
end;
你能想出另一种方法,让这个命令每天以更有效的方式发生一次吗?
谢谢。
答案 0 :(得分:6)
找到解决方案:CRON Scheduler
谢谢LU RD和Runner。
答案 1 :(得分:3)
这是我的示例代码。重要的是要注意比较是在TDateTime值而不是字符串之间进行比较,比较是>=
而不是=
,我谨慎地排除当我不想要它时的那一天,而我跟踪它跑的最后一天。
procedure TForm1.Timer1Timer(Sender: TObject);
var
currentTime: TDateTime;
alarmTime: TDateTime;
begin
// Time is a floating point value with everything to the left of the zero
// representing the days, and everything to the right of the decimal
// point representing time of day
// Date() gets just the day portion, and lastDateExecuted is a global TDateTime
// variable where we store the last day the program ran
// We only go further if it didn't execute today
if (Date > lastDateExecuted) then
begin
// Use Time() instead of Now() to get just the time portion and leave the day
// portion at 0
currentTime := Time;
// Covert our alarm string to TDateTime instead of TDateTime to string
alarmTime := EncodeTime(9, 30, 30, 0);
// Is it time to run?
// Greater than or equal comparison makes the application still run in case
// our timer happens to miss the exact millisecond of the target time
if currentTime >= alarmTime then
begin
// Immediately set the last run date to keep the next timer event
// from repeating this
lastDateExecuted := Date;
// Do your work here
DoMyThing;
end;
end;
end;
请务必将lastDateExecuted值初始化为0。
使用计时器间隔作为粒度。如果您希望它在目标时间的一分钟内运行,请将间隔设置为一分钟。如果您希望它在一秒钟内尝试运行,请将计时器间隔设置为秒。
答案 2 :(得分:1)
如果我理解正确,您需要知道的是如何识别何时达到特定时间才能执行此线程。实际上,定时器不一定是用于此的理想工具,因为定时器实际上并不实时触发(您可以将间隔设置为500毫秒,但是在1分钟或60,000毫秒之后,它将不会完全按照你的意愿完成120次执行。但是,这并不意味着我们不能使用计时器。
在计时器内部(或者您也可以为此创建另一个重复的线程),您只需获取当前日期/时间。重要提示:确保此计时器或线程的间隔小于半秒 - 这将确保您的时间不会错过。所以你会这样读它...
uses
DateUtils;
.....
var
HasExecuted: Bool;
.....
constructor TForm1.Create(Sender: TObject);
begin
HasExecuted:= False;
end;
procedure TimerOnTimer(Sender: TObject);
var
N, A: TDateTime;
Thread: TMyThread;
begin
N := Now;
A := StrToDateTime('11/20/2011 15:30:30'); //24 hour time
//If now is within 1 second over/under alarm time...
if (N >= IncSecond(A, -1)) and (N <= IncSecond(A, 1)) then
begin
if not HasExecuted then begin
HasExecuted:= True;
aThread := tMyThread.Create(true);
aThread.Resume; //The thread will execute once and terminate;
end;
end;
end;
它可能不适合您,因为您使用的是=
运算符。如果这个计时器跳过1秒怎么办?一次执行可能是之前的第二次执行,下一次执行可能是第二次回答,在这种情况下,它不会将此表达式计算为等于true。
另一方面,你的TMyThread
构造函数 - 你是否压倒了这个?如果是,False
仍然是原始的CreateSuspended
参数吗?如果是这样,那么你告诉这个线程在创建时立即执行。在此参数中传递True
以使其在创建时暂停,因为我看到您也在下面调用Thread.Resume
(如果参数保持为false,则它已经恢复)。另一方面,除非已经达到时间,否则您也不需要创建该线程(至少我假设)。你甚至在检查之前为什么要创建它?每次执行此计时器时,它都会创建其中一个(我假设这是根据需要负责上传的线程)。此外,确保线程在完成时正确地释放自己,并且不会卡住......
constructor TMyThread.Create(CreateSuspended: Bool);
begin
inherited Create(CreateSuspended);
FreeOnTerminate:= True; //Make sure it free's its self when it's terminated
end;
修改强>
我错过了一些东西 - 比方说,假设这个计时器的间隔是1(它应该更像是200-400),那么它可以在这段时间内连续多次执行。我修改了上面的代码,也确保它只执行一次。注意:此代码是由内存键入的,而不是在delphi环境中。