Delphi «Будильник», как приложение - PullRequest
5 голосов
/ 30 ноября 2011

Мне нужно сделать простое приложение будильника, которое вместо воспроизведения звука будет загружать файл на 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 ]

6 голосов
/ 30 ноября 2011

Решение найдено : Планировщик CRON

Спасибо LU RD и Runner.

3 голосов
/ 30 ноября 2011

Вот мой пример кода. Важно отметить, что сравнение выполняется между значениями 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.

Используйте интервал таймера для детализации. Если вы хотите, чтобы он работал в течение минуты от целевого времени, установите Интервал в минуту. Если вы хотите, чтобы он работал в течение секунды, установите интервал таймера на секунду.

1 голос
/ 30 ноября 2011

Если я вас правильно понимаю, все, что вам нужно знать, это как распознать, когда достигнуто определенное время для выполнения этой цепочки. Действительно, таймер не обязательно является идеальным инструментом для этого, так как таймеры фактически не срабатывают в режиме реального времени (интервал может составлять 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 ниже этого значения (что, если параметр остается ложным, он уже возобновляется). С другой стороны, вам также не нужно создавать этот поток (по крайней мере, я так предполагаю), если время не истекло. Почему вы создаете это, прежде чем даже проверить? Он создает один из них каждый раз, когда выполняется этот таймер (я предполагаю, что это поток, который по мере необходимости будет заботиться о загрузке). Кроме того, убедитесь, что поток правильно освобождает себя, когда он закончил, а не просто застрял ...

constructor TMyThread.Create(CreateSuspended: Bool);
begin
  inherited Create(CreateSuspended);
  FreeOnTerminate:= True; //Make sure it free's its self when it's terminated
end;

EDIT:

Я что-то упустил - если, скажем, интервал этого таймера был 1 (он должен быть больше как 200-400), то он мог бы очень хорошо выполняться много раз подряд, в течение этого периода времени. Я изменил приведенный выше код, чтобы убедиться, что он выполняется только один раз. ПРИМЕЧАНИЕ. Этот код был набран по памяти, а не в среде Delphi.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...