Я предлагаю вам исследовать Waitable таймеры. Они могут быть настроены на срабатывание по истечении определенного периода времени (например, обычного TTimer) или в указанное время суток, что в точности соответствует именно вам.
В вашей форме создайте/покажите событие, создайте ожидаемый таймер и установите его в требуемое время, которое вы хотите, чтобы он «загорелся» (это будет только один из ваших ближайших кандидатов, т. Е. Следующий из них произойдет после текущее время). В вашем случае, я полагаю, вы упомянули, что обратный отсчет начинается за 90 секунд до закрытия, так что это ваше «время» для ожидаемого таймера (следующий T - 90 секунд).
Необходимое время должно быть указано в FILETIME и должно быть в UTC, а не по местному времени. Это неудобно, но не особенно сложно.
Рассчитать следующее время автоспуска, менее 90 секунд. Затем используйте DateTimeToSystemTime (localTDateTime, localSYSTEMTIME) к полученному TDateTime значение в SYSTEMTIME представления в которой вы можете перейти к TzSpecificLocalTimeToSystemTime() преобразовать в UTC SYSTEMTIME.
Оттуда вы просто затем преобразовать ваш UTC SYSTEMTIME к FILETIME (SystemTimeToFileTime() в SysUtils).
Обратный вызов proc - это первый класс proc, а не метод формы и должен соответствовать ожидаемой сигнатуре обратного вызова.
Обратный вызов будет вызываться в отдельном потоке, поэтому ваша реализация обратного вызова для запуска таймера обратного отсчета должна быть потокобезопасной. Самый простой способ добиться этого - использовать очереди сообщений и просто отправить (или отправить) сообщение в форму, которая в свою очередь отвечает, запустив таймер обратного отсчета. Чтобы обеспечить использование дескриптора правого окна, это может быть передано процессу обратного вызова. Так как HWND вписывается в указатель, вы можете просто передать HWND в указателе напрямую, путем приведения типов.
Ваш обратный вызов прок будет выглядеть примерно так:
procedure TimerCallbackProc(aData: Pointer; aTimerLo, aTimerHi: DWORD);
begin
PostMessage(HWND(aData), MM_STARTCOUNTDOWNTIMER, 0, 0);
end;
Где MM_STARTCOUNTDOWNTIMER является частным, WM_USER на основе сообщений о том, что форма ручки для запуска таймера обратного отсчета:
ПРИМЕЧАНИЕ: Ваша форма должна отменить таймер обратного вызова, когда он закрыт, либо до того, как таймер «выстрелил», либо в результате этого.
Собираем все это вместе, вы должны в конечном итоге что-то вроде:
const
MM_STARTCOUNTDOWNTIMER = WM_USER + 1;
type
TMyForm = class(TForm)
fCloseCountdownTimer: TTimer;
fCloseTimer: HANDLE;
..
procedure MMStartCountdownTimer(var aMessage: TMessage); message MM_STARTCOUNTDOWNTIMER;
end;
procedure TMyForm.FormCreate(Sender: TObject);
begin
..
..
fCloseTimer := CreateWaitableTimer(..);
SetWaitableTimer(fCloseTimer, dueTime, 0, TimerCallbackproc, Pointer(Handle), TRUE);
end;
procedure TMyForm.FormClose(Sender: TObject);
begin
CancelWaitableTimer(fCloseTimer);
end;
procedure TMyForm.MMStartCountdownTimer(var aMessage: TMessage);
begin
fCloseCountdownTimer.Enabled := TRUE;
end;
ПРИМЕЧАНИЕ: Окончательное ИСТИНА параметр в вызове SetWaitableTimer() в коде выше гарантирует, что если система приостанавливается во время срабатывания таймера, затем система будет разбухать для обработки таймера. Если это не то, что вы хотите, просто пропустите FALSE, и таймер не разбудит спящую систему (но ваша форма не будет автоматически закрываться, если время истекло, когда система спала).
Для дальнейших и более конкретных деталей, я предлагаю вам обратиться к Waitable Timer API documentation from Microsoft
Поставьте таймер и индикатор. В интервале таймера вычислите оставшееся время и соответствующим образом обновите индикатор выполнения. Когда вы достигнете 100%, закройте. –
Я не уверен, как это сделать. Вам нужны 2 таймера? Один, чтобы определить время и другое, чтобы манипулировать индикатором выполнения? – user3927897
Какова горизонтальная шкала времени в баре? –