Recent

Author Topic: Cannot stop running TTimer object  (Read 7891 times)

no_shaking

  • Newbie
  • Posts: 5
Cannot stop running TTimer object
« on: May 05, 2014, 03:48:16 pm »
I have an GUI Application, which uses a timer object to loop. Essentially each increment of the timer is the same as increment of a loop.  If a condition is met I wish to stop the timer from within the procedure or anywhere as long as it will work.

I have tried the following methods and functions on the TTimer Class, none have worked. Any suggestions?

procedure DoSomething()
begin
   if some condition = true then
   begin
      //MyForm.Timer1.free;
      MyForm.Timer1.Destroy;
      //MyForm.Timer1.Enabled:=false;
      //MyForm.Timer1.Destroying;
      //MyForm.Timer1._Release;
      //MyForm.Timer1.FreeInstance;
      //MyForm.Timer1.CleanupInstance;       
   end;
end;

procedure TMyForm.Timer1Timer(Sender: TObject);
   begin
      // loop for ever according to timer interval
      DoSomething()
   end;

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12202
  • Debugger - SynEdit - and more
    • wiki
Re: Cannot stop running TTimer object
« Reply #1 on: May 05, 2014, 04:00:08 pm »
Code: [Select]
MyForm.Timer1.Enabled:=false;

Is the recommended way and should work.

However, it may be, that the timer has already been triggered a further time, while your procedure was running. If that is the case, then any event already scheduled by the timer, at the time that you disable it, will still run.

Did you make sure, that the "If" is actually entered?
Like put a
Form1.Caption := 'I am here';
in front of the "timer enabled:=false" line.

Or run in the debugger

no_shaking

  • Newbie
  • Posts: 5
Re: Cannot stop running TTimer object
« Reply #2 on: May 05, 2014, 04:12:28 pm »
I have added a popup message to show that the if condition has been met.

I am getting numerous popups each time the if condition is entered.

See the attached screenshot.

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12202
  • Debugger - SynEdit - and more
    • wiki
Re: Cannot stop running TTimer object
« Reply #3 on: May 05, 2014, 04:22:02 pm »
Well, then without more info, it will be hard to tell why it does not work.


I have used TTimer, and
MyForm.Timer1.Enabled:=false;
has always worked.

What OS are you using? What widget set?
What is the timer interval?

Are you sure your TTimer code finishes, before the next timer fires?

Note, that, if for example the timer interval is 100 (10 times per second), and your code takes half a second, then the Timer1Timer call for the 2nd trigger (after 0.1 seconds) will only run, after your code finished for the first call.

But since the next is already scheduled, setting the timer.enabled to false may not stop that already scheduled call.

Are you sure, you are not enabling the timer in an other place again (yeah sounds like a silly questions, but such kind of mistakes happen to everyone sometimes).

---
Well if none of that helps, then it may be needed to share more of your code.


no_shaking

  • Newbie
  • Posts: 5
Re: Cannot stop running TTimer object
« Reply #4 on: May 05, 2014, 04:51:58 pm »
Environment;
2 GB RAM
Windows 8.1
32 bit
Intel core i3
   
MyForm.Timer1.Interval:=500;

procedure TMyForm.Timer1Timer(Sender: TObject);
   begin
      // loop for ever according to timer interval
      DoSomething()
      if stoptimerflag = true then
         MyForm.Timer1.Enabled:=false;         
   end;
   
I have now moved the Timer close/stop timer call to the original procedure instead of making the call from DoSomething().

But still the Timer does not stop.
« Last Edit: May 05, 2014, 05:15:20 pm by no_shaking »

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Cannot stop running TTimer object
« Reply #5 on: May 05, 2014, 05:58:56 pm »
Environment;
2 GB RAM
Windows 8.1
32 bit
Intel core i3
   
I have now moved the Timer close/stop timer call to the original procedure instead of making the call from DoSomething().

But still the Timer does not stop.

How about this.

Code: [Select]
procedure TMyForm.Timer1Timer(Sender: TObject);
begin
      // loop for ever according to timer interval
     
      MyForm.Timer1.Enabled:=false;         
      DoSomething()
      if not stoptimerflag then
         MyForm.Timer1.Enabled:=Enabled;         
end;
Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

no_shaking

  • Newbie
  • Posts: 5
Re: Cannot stop running TTimer object
« Reply #6 on: May 05, 2014, 06:42:21 pm »
I tried the previous suggestion. I cannot use it.

Scenario: simulation program
Use timer to update / refresh images to mimic animation / simulation

first run sets up the the initial values and calculates the base illustration

normal run takes the values from the first run and keeps running and updating until user ends program or barriers reached then the animation stops
 

Procedure RedrawWeights();
   begin
        TimeInterval := TimeInterval + 1;
   MyForm.TxtGreenX1.Text:=inttostr(MyForm.MovingWeight.Left);
   MyForm.TxtGreenY1.Text:=inttostr(MyForm.MovingWeight.Top);
   MyForm.txtrednewx1.Text:=inttostr(MyForm.PullingWeight.Left);
   MyForm.txtrednewy1.Text:=inttostr(MyForm.PullingWeight.Top);

   ForceMovingWeight:= ForceDisplacement(StrToFloat(MyForm.TxtMovingWeight.Text),StrtoFloat(MyForm.TxtMovingAngle.Text));
   MyForm.txtupwardForceMWF.Text:=Floattostr(ForceMovingWeight);
   ForcePullingWeight := ForceDisplacement(StrToFloat(MyForm.TxtPullingWeight.Text),StrtoFloat(MyForm.TxtPullingAngle.Text));
   MyForm.txtDownwardForcePWF.Text:=Floattostr(ForcePullingWeight);

   movingacceleration:= acceleration(round(ForcePullingWeight), round(ForceMovingWeight));
   MyForm.txtAcceleration.Text:=FloattoStr(Movingacceleration);

   MWTension:=CalcTension(Movingacceleration, ForceMovingWeight);
   MyForm.txttension.text:=FloattoStr(MWTension);
   CurrentVelocityValue:=Velocity(TotalVelocityValue, movingacceleration, TimeInterval);
   DistanceCovered:=Distance(TotalVelocityValue,CurrentVelocityValue, TimeInterval);
   TotalDistanceCovered:=TotalDistanceCovered + (DistanceCovered/10);
   MyForm.txtDistanceCovered.Text:=inttostr(round(TotalDistanceCovered));
   MyForm.txtElapsedTime.Text:=inttostr(TimeInterval);

   //Calculating pullingWeight Angle
   MyForm.txtPullingAngle.Text:=inttoStr(CalcPullingWeightAngle((CalcLength(basex3, basex2, basey3, basey2)), (Basex2-Basex1), (CalcLength(basex3, basex1, basey3, basey1))));

   TotalVelocityValue:=TotalVelocityValue+CurrentVelocityValue;

   //Plot New Location Of Moving Weight (Green)
   TempGradient:=CalcGradient(basex1, basey1, round(basex3), round(basey3));
   TempNewX:=NewX(Distance(TotalVelocityValue,CurrentVelocityValue, TimeInterval), MovingWeightAngle);
   TempNewY:=NewY(round(MyForm.MovingWeight.Left + TempNewX),MyForm.MovingWeight.Left, MyForm.MovingWeight.Top, TempGradient);

   MyForm.MovingWeight.Left:=round(MyForm.MovingWeight.Left + (TempNewX/10));
   MyForm.MovingWeight.Top:=round(MyForm.MovingWeight.Top +  (TempNewY/10));

   //Plot New Location PullingWeight (RED)
   TempGradient:=CalcGradient(basex2, basey2, round(basex3), round(basey3));
   TempNewX:=NewX(Distance(TotalVelocityValue,CurrentVelocityValue, TimeInterval), PullingWeightAngle);
   TempNewY:=NewY(round(MyForm.PullingWeight.Left+TempNewX),MyForm.PullingWeight.Left, MyForm.PullingWeight.Top, TempGradient);

   MyForm.PullingWeight.Left:=round(MyForm.PullingWeight.Left + (TempNewX/10));
   MyForm.PullingWeight.Top:=round(MyForm.PullingWeight.Top + (TempNewY/10));

       //Fixed values for testing only to ensure can stop timer
        if (MyForm.MovingWeight.Left > 720) or (MyForm.MovingWeight.Top > 335) then
        begin
             //MyForm.Timer1.Destroy;
             //StopTimer:=True;
             ShowMessage('ERROR: Cannot kill Pascal application! ');
             //MyForm.Timer1.free;
             //MyForm.Timer1.Destroy;
             //MyForm.Timer1.Enabled:=false;
             //MyForm.Timer1.Destroying;
             //MyForm.Timer1._Release;
             //MyForm.Timer1.FreeInstance;
             //MyForm.Timer1.CleanupInstance;
             StopTimer:=True;
             Exit;
        end;

        // check if TOP barrier reached   (using pulling weight (red))

        if TopBarrierReached(MyForm.PullingWeight.Left,MyForm.PullingWeight.Top) = true then
        begin
                ShowMessage('ERROR: Top Barrier Reached! ');
                StopTimer:=True;
                Exit;
        end;

        // check if TOP barrier reached   (using pulling weight (red))

        if BottomBarrierReached(MyForm.PullingWeight.Left, MyForm.PullingWeight.Top) = true then
        begin
                ShowMessage('ERROR: BottomBarrierReached! ');
                StopTimer:=True;
                Exit;
        end;

   MyForm.TxtRedx1.Text:=inttostr(MyForm.PullingWeight.Left);
   MyForm.TxtRedy1.Text:=inttostr(MyForm.PullingWeight.Top);

   //Draw string
   MyForm.canvas.Pen.Width:=10;
   MyForm.Canvas.Pen.color:= clblack;
   MyForm.canvas.Line(MyForm.MovingWeight.Left+20,MyForm.MovingWeight.Top+10,round(basex3),round(calcbasey3)-40);
   MyForm.canvas.Line(MyForm.PullingWeight.Left+20,MyForm.PullingWeight.Top+10,round(basex3),round(calcbasey3)-40);

   end;

   
// loop for ever

procedure TMyForm.Timer1Timer(Sender: TObject);
   begin

   // for each iteration intialise intermediate variables
      PulleyRadius:=20;
      PullingMidPointx1:= 0;
      PullingMidPointy1:= 0;
      MovingMidPointx1:= 0;
      MovingMidPointy1:= 0;
      newx2 := 0;
      newy2 := 0;
      ForceMovingWeight:=0;
      ForcePullingWeight:=0;
      MWTension:=0;

   // if user has entered values and pressed the submit button
    if SubmitPressed = true then
        begin
            // if first run then set up simulation base screen
                if StartSimulation = true then
                begin
                   InitialRun();
                   DrawTriangle();
                   DrawWeights();
                end
            //if first run then set up simulation base screen
                else
                begin

                   DrawTriangle();
                   DrawWeights();
                   RedrawWeights();

              //MyForm.Timer1.free;
              //Exit;
              //MyForm.Timer1.Destroy;
              //MyForm.Timer1.Enabled:=false;
              //MyForm.Timer1.Destroying;
              //MyForm.Timer1._Release;
              //MyForm.Timer1.FreeInstance;
              //MyForm.Timer1.CleanupInstance;

                end;
        end;
   end;     

taazz

  • Hero Member
  • *****
  • Posts: 5368
Re: Cannot stop running TTimer object
« Reply #7 on: May 05, 2014, 07:01:13 pm »
well the question was does that code stops the loop? if yes then I guess this will solve your problem.
Code: [Select]
procedure TMyForm.Timer1Timer(Sender: TObject);
begin
      stoptimerflag then exit;
      DoSomething()
      if stoptimerflag then
         MyForm.Timer1.Enabled:=false;         
end;

Good judgement is the result of experience … Experience is the result of bad judgement.

OS : Windows 7 64 bit
Laz: Lazarus 1.4.4 FPC 2.6.4 i386-win32-win32/win64

Martin_fr

  • Administrator
  • Hero Member
  • *
  • Posts: 12202
  • Debugger - SynEdit - and more
    • wiki
Re: Cannot stop running TTimer object
« Reply #8 on: May 05, 2014, 07:18:51 pm »
Well, I see you set
Code: [Select]
StopTimer := True

But I see no code that checks it ("if StopTimer then"), nor any timer1.enabled.

Anyway, I am sure that in your initial code it was in there, may be a copy and paste...?

I do not yet know, what you have set the Timer.Interval to?

You have a lot of code in the Timer1Timer (and RedrawWeights).
Compile with console (on windows, see project options, disable "Gui Application", add -WC to custom options /// on linux it is always on)

Add at tthe begin of Timer1Timer
Code: [Select]
var  t1: QWord;
begin
        t1 := GetTickCount64;
and at the end
Code: [Select]
        writeln((GetTickCount64 - t1) / 1000)
then watch the console.

If the integer part of the number printed, is bigger, or close to the interval of your timer, then there is a problem.


Also please make a difference between:
- The Timer does not stop at all. There are endless number of further invocations.
- The timer only stops 5, or 10, or even 100 event calls, after you tried to stop it first.

The 2nd you can fix with the trick by taazz. Your timer tries to invoke the code faster, than the code can finish.

----------------
Other than this, I have not seen anything in the code that would be wrong.

A maybe better way to do this:

- Stop the timer right when you enter the Timer1Timer. SO it will not fire again.
- take the time GetTickCount64
- do one iteratinon (calculate / draw)
- take the end time
- calculate the difference, and run the timer for the remainder of time.

Or in the last step, if you took to long, run the timer on interval 50, so you get to draw, and then calculate that the next iteration must not be 1 iteration but maybe use a factor of 1.3 (whatever amount you used extra time)

User137

  • Hero Member
  • *****
  • Posts: 1791
    • Nxpascal home
Re: Cannot stop running TTimer object
« Reply #9 on: May 06, 2014, 08:00:04 am »
Code: [Select]
ShowMessage('ERROR: Cannot kill Pascal application! ');
MyForm.Timer1.Enabled:=false;
You have to do it other way around. Timer event will not stop waiting till your message dialog has closed, it will trigger it again. So this should do
Code: [Select]
MyForm.Timer1.Enabled:=false;
ShowMessage('ERROR: Cannot kill Pascal application! ');

edit: More precisely... the *current* timer event will stop, but every time the interval ticks it starts a new one.

 

TinyPortal © 2005-2018