Periodicall弹出窗体

时间:2010-09-27 19:07:53

标签: multithreading delphi forms popup timer

我应该定期以其他形式实现弹出窗体。这个弹出窗体不是常见的设计,所以我无法使用标准消息。我需要实现顺利显示\隐藏这个弹出窗体。

现在我使用计时器来隐藏\显示这个表单,但有奇怪的问题。 如果我只运行Show \ Hide popup表单进程一切正常,但是当我尝试在基本表单中运行其他线程时,这对于vcl线程(数学绘画)来说是弹出窗体的行为变得奇怪。

我应该如何在多线程应用程序中使用线程安全弹出窗体?感谢

修改

奇怪的是:我的计时器设置显示show hide形式,期间为5s。 进程开始时一切正常。弹出窗体显示并隐藏超过5s的预期。 但后来我得到了一些弹出窗口(显示弹出窗口)暂停。 然后再次弹出一段时间就可以了(5s) 然后我的计时器间隔无法正常工作。 我同意~4,6s期间。但有时弹出窗口之间没有句号。

3 个答案:

答案 0 :(得分:3)

因为你遗漏了很多重要的信息(“形式表现得很奇怪”可以用大约几十种方式解释,同样多的解决方案),我会去 GUESS 你的问题是,并试图给你一个解决方案。如果我错了,请提供相关信息!

关于TTimer:

当您需要一些定时信号时,TTimer是一个简单的解决方案,但它不应该非常精确。您将计时器设置为在给定的时间间隔内“触发”,Windows将使用配置的周期发送您的应用程序 WM_TIMER 消息。这里的诀窍是,应用程序的队列中不会同时有两条WM_TIMER消息。

如果您要制作一个时钟,并使用TTimer给您1秒的心跳,那么当您的计算机处于空闲状态时,您的时钟将大部分准时,但如果您的计算机正忙,它将会运行缓慢。如果运行时钟的进程忙,那么时钟会运行得更慢。

关于您的问题:

你说的是:

  

如果我只运行Show \ Hide弹出窗体进程一切正常,但是当我尝试在基本窗体中运行其他线程时,这对于vcl线程(数学绘画)来说,弹出窗体的行为变得奇怪。

解释:我假设thread math painting发生在VCL线程中的某个地方,并且阻止了应用程序的消息队列。这是导致您的应用程序跳过WM_TIMER消息,导致the behaviour of popup form become strange

可能的解决方案:

这显然很难,但实际上并不知道问题(再次,奇怪 - 怎么样?),但我会以任何方式给你一些想法。首先让我告诉你,我不认为你可以使用更好的计时器解决你的问题。您的问题与GUI相关,GUI是单线程的。虽然你确实有一些后台线程正在做一些事情,但他们需要marshall to vcl thread - 无论你的计时器有多精确,它都无法阻止主VCL线程执行marshall事情,所以计时器需要等待marshall完成才能完成需要做的事情。

I need implement smoothly showing\hiding of this popup form处获取提示我假设您需要为smooth showing\hiding执行一些步骤,这就是您使用TTimer的步骤。

如果你有这样的代码: (警告,这是伪代码,我怀疑它编译)

procedure Timer1OnTimer(Sender:TObject);
begin
  SomeCounter := SomeCounter + 1;
  if SomeCounter > 10 then
    HidePopupForm
  else
    SetPopupFormTransparencyTo((SomeCounter * 255) div 10);
end;

用以下内容替换它:

var HideAtTime:TDateTime;
    ShownAtTime:TDateTime;

procedure Timer1OnTimer(Sender:TObject);
var ExpectedVisibleTime:TDateTime;
    ElapsedVisibleTime:TDateTime;
begin
  if Now > HideAtTime then
    HidePopupForm
  else
    begin
      ExpectedVisibleTime := HideAtTime - ShownAtTime;
      ElapsedVisibleTime := Now - ShownAtTime;
      SetPopupFormTransparencyTo(ElapsedVisibleTime/ExpectedVisibleTime*255);
    end;
end;

这个解决方案的一般想法是计算截止日期,将它们存储在TDateTime变量中,与TTimer.OnTimer中的Now进行比较;这样,如果计时器事件没有按照要求的时间间隔到达,那么你将大部分按时完成所有其他操作。当然,显示一个表单可能不是那么顺利,但它会完成工作。

答案 1 :(得分:0)

您是否尝试过使用备用定时器? 库存VCL计时器使用主消息队列,这意味着如果您的消息队列被发布数以万计的消息的其他线程阻塞,则实际时间与实时完全不同。

答案 2 :(得分:0)

感谢好的Cosmin Prund帖子,我解决了我的问题。问题是:后台线程有很小的数学运算,经常(循环)编组到VCL线程。因此,在执行后台线程的过程中,它总是绘制其结果线程安全的方式。

因为vcl线程非常“忙”而且

background threads it can't stop the main VCL thread from doing the marshall thing, 
so the timer will need to wait for the marshall to finish in order to do what
needs to be done.

好的我决定让我的bacjground线程更加独立于vcl并粘贴

 Sleep(50);

在我的执行方法中。 好的,我的定时器有“正常”:)行为。

但我不满意新的vcl线程反应。所以我决定在线程上构建位图,并在同步时将其分配给gui,而不是在同步时进行画布操作。这样我就可以期待vcl反应和弹出行为。谢谢大家。