views:

102

answers:

3

Hello. I should implement periodically popup form at other form. This popup form isn't common design, so I couldn't use standard messages. I need implement smoothly showing\hiding of this popup form.

Now I use timers for hide\show this form, but have strange problems. If I run only Show\Hide popup form process all is OK, but when I try run other threads at base form,which are marshling to vcl thread (math painting) behaviour of popup form become strange.

How should I imlement thread-safe popup form at multi-thread app? Thanks

EDIT

Strange thing: My timers setup show show hide form with period 5s. When process starts all is ok. Popup form is show and hide over 5s as expecting. But then I got some cycles of popup(show popup from) withous pause. Then again period of popup is OK(5s).
Then my timer intervals don't work correctly. I agree with ~4,6s period. But sometimes there is no periods between popup.

A: 

Have you tried to use alternate timers?
The stock VCL Timers use the main message queue which means that if your message queue gets clogged by the other threads posting zillions of messages, the actual timing is completely off from real time.

François
+3  A: 

Because you left out a lot of important information ("form is behaving strange" can be interpreted in about a zillion ways, with just as many solutions), I'm going to GUESS what your problem is, and attempt giving you a solution. Please provide relevant information if I'm wrong!

About the TTimer:

The TTimer is a simple solution when you need some timing signals but it's not supposed to be very precise. You set up the timer to "fire" at the given Interval, and Windows will send your application WM_TIMER messages with the configured periodicity. The trick here is, there will never be two WM_TIMER messages on your application's queue at the same time.

If you were to make an clock, and used an TTimer to give you a 1 second heart-beat, your clock would be mostly on time when your computer is idle but it will run slow if your computer is busy. If the processes running the clock is busy the clock would run even slower.

About your problem:

You're saying:

If I run only Show\Hide popup form process all is OK, but when I try run other threads at base form,which are marshling to vcl thread (math painting) behaviour of popup form become strange.

Interpretation: I assume the thread math painting is happening somewhere in the VCL thread, and that's blocking your application's message queue. This is turn is causing your application to skip WM_TIMER messages, causing the behaviour of popup form become strange.

Possible solutions:

This is obviously tough without actually knowing the problem (again, strange - how?), but I'm going to give you some ideas any way. First of all let me tell you, I don't think you can fix your problem using a better timer. Your problem is GUI related, and the GUI is single-threaded. While you do have some background threads doing some stuff, they need to marshall to vcl thread - no matter how precise your timer is, 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.

Taking hint from I need implement smoothly showing\hiding of this popup form I assume you need an number of steps for your smooth showing\hiding, and that's what you're using the TTimer for.

If you got code like this: (warning, this is pseudo-code, I doubt it compiles)

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

Replace it with something like this:

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;

The general idea with this solution is to compute deadlines, store them in TDateTime variables, compare with Now from your TTimer.OnTimer; That way it doesn't matter if the timer events don't arrive at the requested intervals, you'd be mostly on time with everything else. Sure, showing up a form might not be as smooth as desired, but it'll get the job done.

Cosmin Prund
I'd vote +2 if I could - not only did you point out what he needs to address to ask a better question, but you took a good stab at providing an answer anyway. Nice work.
David M
+1; as per David's comment.
Jeroen Pluimers
Ok! I describe strange thing. Great thanks for your post. As i understand I got problem with queue WM_TIMER. But on the other hand you said "there will never be two WM_TIMER messages on your application's queue at the same time", and I can't explain popup form without intervals. Anyway thanks a lot
Andrew Kalashnikov
Not only will there never be two `WM_TIMER` messages in the queue, there will never be one either. `WM_TIMER` and `WM_PAINT` are synthesized messages, synthesized only when a message is requested from an empty message queue. A good explanation can be found in http://www.codeproject.com/KB/system/simpletime.aspx?msg=1946497, in the section "WM_TIMER".
mghie
A: 

Thanks to nice Cosmin Prund post, I resolve my issue. The problem was: background thread has small math procession and frequently(in loop) marshalled to VCL thread. So almoast all the time of executing background thread it paints of its result thread-safe way.

Because vcl thread was very "busy" and

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.

Ok I decide make my bacjground thread more vcl independent and paste

 Sleep(50);

at my execute method. Ok I get "normal" :) behaviour of my timers.

But I don't be satisfied new vcl thread reaction. So I decide build bitmap at thread and assign it to gui at synchronize instead canvas manipulation at synchronize. This way I get expecting vcl reaction and popup behaviuor. Thanks for all.

Andrew Kalashnikov