Delphi 我应该在OnIdle处理程序或计时器中进行定期检查吗?

Delphi 我应该在OnIdle处理程序或计时器中进行定期检查吗?,delphi,Delphi,我想在一段时间不活动后将用户注销我的应用程序 在应用程序的OnIdle处理程序或计时器处理程序中检查不活动是否更好 粒度并不太重要。注销可以是正负几秒钟,甚至可能是一分钟 我感觉应用程序的OnIdle将频繁启动。有什么建议吗?代码本身只有几行。为什么不让Windows为您这样做 有一些策略会在用户想要重新开始工作时自动启动屏幕保护程序并强制登录 从Windows7开始,你不能使用咖啡因或其他键盘模拟器等工具来解决这些问题 这使得它比您在Delphi应用程序中所能做的任何事情都要紧密得多。我个人使

我想在一段时间不活动后将用户注销我的应用程序

在应用程序的OnIdle处理程序或计时器处理程序中检查不活动是否更好

粒度并不太重要。注销可以是正负几秒钟,甚至可能是一分钟


我感觉应用程序的OnIdle将频繁启动。有什么建议吗?代码本身只有几行。

为什么不让Windows为您这样做

有一些策略会在用户想要重新开始工作时自动启动屏幕保护程序并强制登录

从Windows7开始,你不能使用咖啡因或其他键盘模拟器等工具来解决这些问题


这使得它比您在Delphi应用程序中所能做的任何事情都要紧密得多。

我个人使用以下方法

GetLastInputInfo来自Windows,并给出一个结果,告诉您有多长时间没有键盘或鼠标活动

TimerLogoffTimer是设置为每5秒触发一次的计时器

TimeoutValue是我从配置中读取的值

DoLogoff是一个执行关闭表单等实际工作的程序

function SecondsIdle: DWord;
var
  liInfo: TLastInputInfo;
begin
  liInfo.cbSize := SizeOf(TLastInputInfo) ;
  GetLastInputInfo(liInfo) ;
  Result := (GetTickCount - liInfo.dwTime) DIV 1000;
end;

procedure TfrmMain.TimerLogoffTimer(Sender: TObject);
begin
  if SecondsIdle >= DWord(TimeoutValue) then
    DoLogoff;
end;

您正在使用GetLastInputInfo测量空闲时间。这似乎很明智。所以问题归结为

我应该在OnIdle处理程序或计时器中进行定期检查吗

每次消息队列清空时,OnIdle都会激发。如果队列中没有消息,OnIdle将永远不会触发。所以,OnIdle不是周期性的。如果您想定期检查不活动状态,那么OnIdle可能不起作用。计时器一定会工作

您可以这样想:当空闲计数器启动时触发OnIdle事件,但当空闲计数器过期时需要触发一个事件

我感觉应用程序的OnIdle即将启动 太频繁了

事实上,你的问题恰恰相反



请注意,您可能对此进行了实验,并发现OnIdle似乎工作正常,并且可以定期点火。例如,如果您的应用程序使用任何计时器,则OnIdle将在每个计时器事件后触发。因为计时器事件出现在队列中,并且一旦处理完毕,就会触发OnIdle。但是,如果你的应用程序没有计时器,那么如果你停止与你的程序交互,你可以期望OnIdle完全不会启动。

TTimer使用Windows内部资源,这在当今千兆字节和千兆字节的世界中可能没什么大不了,但仍然不太好

我会尝试使用OnIdle或MainForm。为它采取行动-

这两种方法可能都需要稍微降低一点-

注意那些关于TApplication.OnIdle的行-这可能是 自链接事件,用于在之后将stup no op消息发布到应用程序 每个循环:

除非使用Done参数,否则不会连续调用它 设置为false。将Done设置为false的应用程序使用 CPU时间过多,影响整个系统 表演


几天前在Embarcadero论坛上讨论了OnIdle vs TTimer的问题:

特别是,在该讨论中,解释了
TApplication.OnIdle
事件的实际工作方式,以及设置
Done
参数的实际含义:

我知道当应用程序 开始闲置

每次应用程序进入新的空闲状态时都会调用它。每一次 主消息循环用于从主消息队列检索消息 并且还没有消息出现,OnIdle事件被触发,主 线程进入睡眠状态,直到新消息到达队列。一旦 消息在队列再次变为空时被处理,即OnIdle事件 再次触发,主线程休眠,直到新消息到达, 等等

function SecondsIdle: DWord;
var
  liInfo: TLastInputInfo;
begin
  liInfo.cbSize := SizeOf(TLastInputInfo) ;
  GetLastInputInfo(liInfo) ;
  Result := (GetTickCount - liInfo.dwTime) DIV 1000;
end;

procedure TfrmMain.TimerLogoffTimer(Sender: TObject);
begin
  if SecondsIdle >= DWord(TimeoutValue) then
    DoLogoff;
end;
如果我使用它,我的检查过程将只调用一次,然后 系统将继续等待用户输入,无需再次检查

在OnIdle事件处理程序中,可以将Done参数设置为False以防止 当没有消息时,主线程将无法进入睡眠状态 处理。这将允许OnIdle事件在 队列中没有新消息。然而,这也有其一面 但禁用TAction.OnUpdate事件的影响

我想做的是更新计时器的显示

然后,您应该使用一个真正的计时器广告,在每次计时器启动时更新UI 过去了

随着剩余时间的变化,它需要不断地重新绘制自己。也许有 另一种更简单/更好的方法

查看TTimer组件及其OnTimer事件


+抱歉,我应该说“我想让用户退出我的应用程序”+1是的,这和我用来获取空闲时间的代码是一样的。有什么理由你更喜欢定时器而不是应用程序的OnIdle hendler吗?没有什么特别的原因-这一直对我有效,所以我没有理由改变它:-)确实有理由使用定时器而不是OnIdle。根据我的回答。关于此代码功能的问题:在一次测试中,我通过计时器事件将secondsidle函数的结果放入任务栏条目,然后最小化窗体并执行其他操作。我注意到它大部分时间都是0,除了我没有在其他窗口做任何事情的时候。那么GetLastInputInfo函数是系统的全局函数还是应用程序的本地函数?如果它是本地的,那么这是否就是解决方案,因为当我在其他地方工作时,窗口可能会收到消息,使其停留在0?@Glenn-它不是应用程序的本地,它检索应用程序调用api.TApplication.OnIdle文档的会话中最后一次输入时间,该文档提示处理程序的参数,你可以用它来决定这是否是一次性的