在一天中的某些时间关闭表单 [英] Close the form on certain hours of the day

查看:63
本文介绍了在一天中的某些时间关闭表单的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望我的表格在时间06:00、12:00和24:00关闭.但是在关闭之前,我想显示一个进度条,其中显示表单关闭前还剩下多少时间(进度如何条达到100%-表格关闭).我该怎么办?

I would like my form to close when the time is 06:00, 12:00 and 24:00. But before it closes I would like to display a progress bar showing how much time is remaining before the form closes (When the progress bar reaches 100% - the form closes). How can I do this?

我正在这样做:

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;

所以我需要的也许是另一个计时器,它将检测一天中的时间并在指定的时间触发进度条(Timer1.Enabled:= True;).您如何在代码中检测正确的时间?

So what I need is perhaps another timer which would detect the time of the day and fire on designated time the progress bar (Timer1.Enabled := True;). How do you detect the right time in code?

推荐答案

我建议您研究等待计时器.可以将它们设置为在特定时间段(例如常规TTimer)之后或一天中的指定时间触发,这正是您在这种情况下需要的.

I suggest you investigate Waitable timers. These can be set to set to fire after a specific period of time (like a regular TTimer) or at a specified time of day, which is exactly what you need in this case.

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

In your form create/show event, create a waitable timer and set it to the required time that you wish it to 'fire' (it will be only one of your candidate close times, i.e the next one to occur after the current time). In your case I believe you mentioned the countdown starts 90 seconds before the close time, so this is your "due time" for the waitable timer (next T - 90 secs).

您设置的到期时间必须在 FILETIME 中指定,并且必须使用UTC而不是本地时间.这很奇怪,但并不是特别困难.

The due time you set must be specified in FILETIME and must be in UTC, not local time. This is fiddly, but not especially difficult.

计算下一个自动关闭时间,少于90秒.然后将 DateTimeToSystemTime(localTDateTime,localSYSTEMTIME)用作 SYSTEMTIME 表示形式的结果 TDateTime 值,然后将其传递给

Calculate the next auto close time, less 90 seconds. Then use DateTimeToSystemTime(localTDateTime, localSYSTEMTIME) to the resulting TDateTime value in a SYSTEMTIME representation which you can then pass to TzSpecificLocalTimeToSystemTime() to convert to a UTC SYSTEMTIME.

从那里您只需将您的UTC SYSTEMTIME 转换为 FILETIME ( SysUtils 中的 SystemTimeToFileTime()).

From there you simply then convert your UTC SYSTEMTIME to FILETIME (SystemTimeToFileTime() in SysUtils).

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

The callback proc is a first class proc, not a form method, and must conform to the expected callback signature.

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

The callback proc will be called in a separate thread so your callback implementation to start the countdown timer must be thread safe. The simplest way to achieve this is to exploit message queues and simply send (or post) a message to the form which in turn responds by starting the countdown timer. To ensure the right window handle is used, this can be passed to the callback proc. Since a HWND fits in a pointer you can just pass the HWND in the pointer directly, by typecasting.

您的回调过程将如下所示:

Your callback proc will look something like this:

procedure TimerCallbackProc(aData: Pointer; aTimerLo, aTimerHi: DWORD);
begin
  PostMessage(HWND(aData), MM_STARTCOUNTDOWNTIMER, 0, 0);
end;

MM_STARTCOUNTDOWNTIMER 是基于 WM_USER 的私人消息,表单将处理该消息以启动倒数计时器:

Where MM_STARTCOUNTDOWNTIMER is a private, WM_USER based message that the form handles to start the countdown timer:

注意:您的表单必须在关闭时(在触发"之前或由于其结果而取消)取消回调计时器.

NOTE: Your form must cancel the callback timer when it is closed, either before the timer has 'fired' or as a result of it.

将所有内容放在一起,最终应该得到以下内容:

Putting all of that together, you should end up with something like:

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()的调用中的最后一个 TRUE 参数可确保如果在定时器触发时系统被挂起,则系统将唤醒以处理计时器.如果这不是您想要的,则只需通过FALSE,计时器就不会唤醒睡眠中的系统(但是,如果系统处于睡眠状态时,到期时间已经过去或消失,您的表单现在将不会自动关闭).

NOTE: The final TRUE parameter in the call to SetWaitableTimer() in the code above ensures that if the system is suspended at time that the timer fires, then the system will wake in order to process the timer. If this is not what you want, then simply pass FALSE, and the timer will not wake a sleeping system (but your form will not now close automatically if the due time has been and gone while the system was asleep).

有关更多详细信息,建议您参考

For further and more specific details, I suggest you refer to the Waitable Timer API documentation from Microsoft

这篇关于在一天中的某些时间关闭表单的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆