在一天中的某些时段关闭表格

use*_*897 -2 delphi

我希望我的表格在06:00,12:00和24:00结束时关闭.但在关闭之前,我想显示一个进度条,显示表单关闭前剩余的时间(当进度条达到100%时 - 表单关闭).我怎样才能做到这一点?

编辑:我这样做:

procedure TMainForm.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := False;
 AdvOfficeStatusBar1.Panels[4].Progress.Position := AdvOfficeStatusBar1.Panels[4].Progress.Position +1;
 if AdvOfficeStatusBar1.Panels[4].Progress.Position = 100 then begin
 MainForm.Close;
 end;
 Timer1.Enabled := True;
end;
Run Code Online (Sandbox Code Playgroud)

所以我需要的可能是另一个计时器,它可以检测当天的时间并在指定的时间点击进度条(Timer1.Enabled:= True;).你如何在代码中检测到合适的时间?

Del*_*ics 5

我建议你调查Waitable计时器.这些可以设置为在特定时间段(如常规TTimer)之后或在一天中的指定时间触发,这正是您在这种情况下所需的.

在您的表单创建/显示事件中,创建一个等待计时器并将其设置为您希望"触发"的所需时间(它将只是您的候选关闭时间之一,即下一个在当前时间之后发生) .在你的情况下,我相信你提到在倒闭时间前90秒开始倒计时,所以这是你的等待计时器的"到期时间"(下一个T - 90秒).

您设置的截止时间必须在FILETIME中指定,并且必须是UTC,而不是本地时间.这很繁琐,但并不是特别困难.

计算下一个自动关闭时间,减去90秒.然后将DateTimeToSystemTime(localTDateTime,localSYSTEMTIME)用于SYSTEMTIME表示形式的结果TDateTime值,然后您可以将其传递给TzSpecificLocalTimeToSystemTime()以转换为UTC SYSTEMTIME.

从那里,你只需再转换你的UTC SYSTEMTIMEFILETIME(SystemTimeToFileTime()SysUtils单元).

回调proc是第一类proc,而不是form方法,并且必须符合预期的回调签名.

回调proc将在一个单独的线程中调用,因此启动倒计时器的回调实现必须是线程安全的.实现这一目标的最简单方法是利用消息队列并简单地将消息发送(或发布)到表单,然后通过启动倒数计时器来响应.为了确保使用正确的窗口句柄,可以将其传递给回调过程.由于HWND适合指针,因此可以通过类型转换直接传递指针中的HWND.

你的回调过程看起来像这样:

procedure TimerCallbackProc(aData: Pointer; aTimerLo, aTimerHi: DWORD);
begin
  PostMessage(HWND(aData), MM_STARTCOUNTDOWNTIMER, 0, 0);
end;
Run Code Online (Sandbox Code Playgroud)

其中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;
Run Code Online (Sandbox Code Playgroud)

注意:上面代码中对SetWaitableTimer()的调用中的最后一个TRUE参数确保如果系统在计时器触发时暂停,则系统将唤醒以处理计时器.如果这不是您想要的,那么只需传递FALSE,并且计时器不会唤醒睡眠系统(但是如果在系统处于睡眠状态时已经过去了,您的表单将不会自动关闭).

有关更多更具体的细节,我建议您参考MicrosoftWaitable Timer API文档

  • 我试图提供足够的细节来指导它们.如果对OP来说有点延伸,这可能是一件好事 - 毕竟,伸展自己是一种有效的学习方式.:) (2认同)