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 n开发者_如何学编程o periods between popup.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.
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.
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.
精彩评论