Delphi 德尔福';闹钟'-相似应用

Delphi 德尔福';闹钟'-相似应用,delphi,scheduled-tasks,Delphi,Scheduled Tasks,我需要做一个简单的闹钟应用程序,而不是播放声音,将上传一个文件到ftp(得到后者的计算)计时器在执行线程时被证明是无效的 以下是我目前得到的信息: var ttime : tDateTime; timerstr : string; timealarm : string; aThread : TMyThread; begin aThread := tMyThread.Create(false); ttime := Now; timestr := FormatDateTime('hh:nn

我需要做一个简单的闹钟应用程序,而不是播放声音,将上传一个文件到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;
你们能想出另一种更有效的方法让命令每天执行一次吗


谢谢。

如果我没弄错的话,您所需要知道的就是如何识别何时达到了执行此线程的特定时间。事实上,计时器不一定是实现这一点的理想工具,因为计时器实际上不会实时触发(您可以将间隔设置为500毫秒,但在1分钟或60000毫秒后,它将不会像您希望的那样完美地排列到精确的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(应该更像是200-400),那么它很可能在这个时间段内连续执行多次。我修改了上面的代码,以确保它只执行一次。注意:此代码是通过内存输入的,而不是在delphi环境中。

这是我的示例代码。需要注意的是,比较是在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的值


根据您的粒度使用计时器间隔。如果希望它在目标时间的一分钟内运行,请将间隔设置为一分钟。如果希望它在一秒钟内运行,请将计时器间隔设置为一秒钟。

找到的解决方案


谢谢路路和跑步者。

如果你做得好,计时器会工作得很好。另一种选择是,在我看来,这是睡眠的唯一合适用例。我我会像nature预期的那样使用系统任务调度程序。下面是LU RD的链接答案中的一些选项,关于Microsoft API的答案看起来很完美。这样一来,你的应用程序就不必撒谎等待,它可以在该运行的时候运行。只是一个稍微无关的小提示-尽量避免声明名为例如
ttime
的变量,因为
ttime
实际上是一个类型,如果你决定使用该类型
ttime
,它可能会抛开一切。Delphi不像C#等其他语言那样区分大小写。在C#中,这将是非常好的(除了C#在类型前面不使用
t
),如果这是一个一次性事件,您也可以只检查
if(N>=A)
。这将检查它是否已经过了那个时间,但使用前面提到的“HasExecuted”检查,它将确保在整个应用程序期间执行一次。当然,如果这件事每天都在同一时间发生的话,我们还可以做得更多。沃伦,谢谢你指出这一点,但是,我不明白这有什么关系。我提供的是我手动输入的粗略代码,而不是最终代码。Jerry,我的线程工作得很好,以FreeOnTerminate开始,以Terminate结束,因此它只执行一次。您的代码不工作,因为“11/29/2011 15:30:30”返回错误。像“15:30:30”这样做不会返回该错误,但它也不起作用,尝试找出它。好吧,这是代码中不相关的部分,就像我说的,我是通过内存输入的。将日期/时间转换为字符串和从字符串转换为日期/时间是一个不同的故事,不同的问题。我们这里不需要字符串,这个属性可能是其他的东西。在这种情况下,我相信你没有具体说明你需要帮助这个项目的哪一部分。我认为这与计时器的使用有关。实际上,根据经验,我不得不建议将计时器间隔设置为略低于所需的间隔。如果希望在一分钟内执行此操作,请将间隔设置为略少于一分钟。这是因为计时器与实际时间不完全一致,可能会错过一秒或几毫秒(但错过你想要的时间将是一场灾难)@Jerry,我同意。我通常将我想要的感知粒度除以2。因此,如果我想让用户感觉到它会在一分钟内触发事件,我会将间隔设置为30秒。我的帖子已经很长了,我没有费心去讨论,但这是一个有效的观点。而且,通过我的实现,您不会完全错过警报。+1。使用调度程序,您甚至可以将计算机设置为在关闭时启动。这是最佳的解决方案。我们已经使用CRON调度器和Chromis目录监视有一段时间了,以后再也不会使用了。优秀的软件。
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;