德尔福'闹钟'般的应用程序

时间:2011-11-29 23:58:56

标签: delphi scheduled-tasks

我需要制作一个简单的闹钟应用程序,它不会播放声音,而是将文件上传到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;

你能想出另一种方法,让这个命令每天以更有效的方式发生一次吗?

谢谢。

3 个答案:

答案 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环境中。