考虑在给定按钮的OnClick事件中执行的以下代码:
procedure TForm1.Button1Click(Sender: TObject);
begin
button1.enabled := false; //Line 1
application.processmessages; //Line 2
Sleep(3000); //Line 3
button1.enabled := True; //Line 4
Release; //Line 5
end;
在Delphi 2010中,如果单击此按钮后您又设法执行另一个按钮 在第3行执行繁忙时单击它,随后单击 事件显然会存储在命令队列中,因此 调用Release(第5行)程序,应用程序将尝试处理 它。因此,将再次触发点击事件。第二次 周围,按钮组件已经被破坏,因此“访问违规”错误被提出。
整个概念确认系统在第二次点击时各自 按钮被禁用似乎没有声音。对这种阴暗行为的任何解释?
答案 0 :(得分:4)
系统的行为与设计完全一致,但要注意您的代码违反所有声音设计原则。具体而言,在输入事件处理程序中使用Sleep
和ProcessMessages
都是不受欢迎的。
程序以这种方式运行的原因如下:
OnClick
处理程序返回,应用程序的消息循环继续。CM_RELEASE
消息之前),因此按钮OnClick
处理程序再次运行。OnClick
处理程序调用{{1}}然后处理ProcessMessages
并杀死表单。当相应按钮被禁用时,确认系统第二次点击的整个概念似乎不合理。
关键是当输入消息处理时检查按钮的启用状态,而不是输入消息生成时检查。它必须是这种方式,因为输入消息是非常低级的东西,并且只有应用程序可以将它们解释为按钮点击之类的东西。
有很多方法可以修复你的代码,但我不愿意提出任何建议,因为这显然是用于说明的代码。但我会说所有声音解决方案都将涉及删除对CM_RELEASE
和`ProcessMessages的调用。
答案 1 :(得分:0)
在睡眠期间,您的应用程序无响应。单击消息排队,仅在重新启用按钮后处理(实际上在事件处理程序方法完全执行且应用程序再次空闲之后)。
要解决此问题,请在启用睡眠后执行Application.ProcessMessages,然后再启用该按钮。这将首先清空您的邮件队列,并将丢弃单击邮件。
或者根本就不要启用按钮。如果你打算发布表格,为什么会这样呢?
一个(可能)更好的解决方案是在一个单独的线程中执行Sleep,但由于这里的Sleep可能只是一些实际代码的存根,所以很难说它需要付出多少努力才能做到这一点。
无论如何,你当前的应用程序并不好,在这种情况下调用Application.ProcessMessages很可能会偶尔产生“随机”错误。你能做的最好的事情就是限制风险,但除了从根本上改变这种实现之外,没有好办法解决它。