Recent

Author Topic: Frame rate in "TGifAnim" object [SOLVED]  (Read 3325 times)

pascal111

  • Sr. Member
  • ****
  • Posts: 423
  • Un trabajo en equipo para programas serias.
Frame rate in "TGifAnim" object [SOLVED]
« on: May 06, 2021, 01:51:10 pm »
I was searching in "TGifAnim" component for a property or a method to adjust the frame rate, but I think I didn't get the idea of how this component can be adjust for this purpose.

(https://i.postimg.cc/rDS857F9/Screenshot-at-2021-05-06-13-47-26.png)
« Last Edit: May 06, 2021, 07:46:14 pm by pascal111 »
La chose par la chose est rappelé.

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: Frame rate in "TGifAnim" object
« Reply #1 on: May 06, 2021, 02:45:26 pm »
You can turn off automatic animations (GifAnim1.Animate := false), add a timer, and in its OnTimer event call Gifanim1.NextFrame. Set the timer's Interval according to the required frame rate.
« Last Edit: May 06, 2021, 02:51:12 pm by wp »

pascal111

  • Sr. Member
  • ****
  • Posts: 423
  • Un trabajo en equipo para programas serias.
Re: Frame rate in "TGifAnim" object
« Reply #2 on: May 06, 2021, 03:08:41 pm »
You are absolutely right!

Code: Pascal  [Select][+][-]
  1. procedure TForm1.Timer1Timer(Sender: TObject);
  2. begin
  3.  
  4.   gifanim1.NextFrame;
  5.   Invalidate;
  6.  
  7. end;  
  8.  
La chose par la chose est rappelé.

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: Frame rate in "TGifAnim" object
« Reply #3 on: May 06, 2021, 03:22:54 pm »
No need to "Invalidate" because the TGifAnim automatically repaints itself when the next frame is loaded:

Code: Pascal  [Select][+][-]
  1. procedure TGifAnim.NextFrame;
  2. begin
  3.   if (not FEmpty) and Visible and (not FAnimate) then
  4.   begin
  5.     if FCurrentImage >= GifBitmaps.Count - 1 then
  6.       FCurrentImage := 0
  7.     else
  8.       Inc(FCurrentImage);
  9.     if Assigned(FOnFrameChanged) then
  10.       FOnFrameChanged(Self);
  11.     Repaint;  
  12.   end;
  13. end;

BTW, there's also a TGifAnim.PriorFrame. Following the same principle you can render an animation in reverse order.

pascal111

  • Sr. Member
  • ****
  • Posts: 423
  • Un trabajo en equipo para programas serias.
Re: Frame rate in "TGifAnim" object
« Reply #4 on: May 06, 2021, 03:44:58 pm »
From where you got the definition of  "TGifAnim.NextFrame" procedure?

I tried to use "TGifAnim.PriorFrame" to reverse the motion but it failed:

Code: Pascal  [Select][+][-]
  1.  
  2. procedure TForm1.Button3Click(Sender: TObject);
  3. begin
  4.   gifanim1.PriorFrame;
  5. end;    
  6.  
  7.  
La chose par la chose est rappelé.

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: Frame rate in "TGifAnim" object
« Reply #5 on: May 06, 2021, 04:33:51 pm »
From where you got the definition of  "TGifAnim.NextFrame" procedure?
From the source code. Type TGifAnim somewhere in your source, hold the CTRL key down and left-click on this word --> the IDE will open the file for you in which the word is declared. Likewise, CTRL-click on the "NextFrame" in "GifAnim1.NextFrame" and the IDE will move you to the declaration or implemantion of TGifAnim1.NextFrame. Press CTRL+SHIFT+Up/Down to jump between interface and implementation

I tried to use "TGifAnim.PriorFrame" to reverse the motion but it failed

Code: Pascal  [Select][+][-]
  1.  
  2. procedure TForm1.Button3Click(Sender: TObject);
  3. begin
  4.   gifanim1.PriorFrame;
  5. end;    
  6.  
  7.  
You must call PriorFrame in the OnTimer event handler, like you did with NextFrame. Maybe you should have a look at my attached demo in which you can click a button to toggle between forward and backward rendering and in which you can roughly change the frame rate (timer interval) by means of a TrackBar.
« Last Edit: May 06, 2021, 04:37:37 pm by wp »

pascal111

  • Sr. Member
  • ****
  • Posts: 423
  • Un trabajo en equipo para programas serias.
Re: Frame rate in "TGifAnim" object
« Reply #6 on: May 06, 2021, 05:45:32 pm »
I spent time to get the idea of this chunk of code:

Code: Pascal  [Select][+][-]
  1. procedure TForm1.TrackBar1Change(Sender: TObject);
  2. const
  3.   INTERVALS: array[0..5] of Integer = (1000, 300, 100, 40, 20, 10);
  4. begin
  5.   Timer1.Interval := INTERVALS[Trackbar1.Position];
  6.   Label1.Caption := Format('Interval %d ms --> %.0f frames/s', [
  7.     INTERVALS[Trackbar1.Position],
  8.     1000.0/INTERVALS[Trackbar1.Position]
  9.   ]);
  10. end;        
  11.  

You used "format", this is new to me, it's like C++ style. You assigned values to the array at the declaration section.

Ok, what about next line, why you made the sender "nil" in "Trackbar1Change" and why you called it in "FormCreate"?

Code: Pascal  [Select][+][-]
  1. procedure TForm1.FormCreate(Sender: TObject);
  2. begin
  3.   Trackbar1Change(nil);
  4. end;  
  5.  
« Last Edit: May 06, 2021, 05:48:40 pm by pascal111 »
La chose par la chose est rappelé.

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: Frame rate in "TGifAnim" object
« Reply #7 on: May 06, 2021, 06:40:41 pm »
/1/ INTERVALS array

When you scroll the Trackbar its Position property varies between its Min and Max values - they are 0 and 5 in this example. I am using the INTERVALS array to prepare an interval value for the timer for each step of the Trackbar. When the trackbar is at the left (Position = 0) the Timer.Interval becomes INTERVALS[0] = 1000, the longest interval, i.e. very slow rendering. Or when the trackbar is at the right (Position =5) then the Timer.Interval becomes 10 ms, the shortest interval, i.e. very fast renderung. Spending more typing work and probably requiring a bit more memory you could achieve the same effect by
Code: Pascal  [Select][+][-]
  1. case TrackBar1.Position of
  2.   0: Timer1.Interval := 1000;
  3.   1: Timer1.Interval := 300;
  4.   2: Timer1.Interval := 100;
  5.   3: Timer1.Interval := 40;
  6.   4: Timer1.Interval := 20;
  7.   5: Timer1.Interval := 10;
  8. end;

/2/ Format function

Yes, this function probably has the spirit of C in mind, but it is extremely useful. It has two arguments: the format mask string, and the argument list. The mask string contains symbol such as %s or %d, and they are replaced by the corresponding values from the argument list which is given as an array. %s is replaced by a string, %d is replaced by an integer value, %f by a floating point value (in this latter case the count of decimal places is given by the number before the "f" - "%.0f" means: "show the float with 0 decimals"). You must be careful to provide the value list in the same order as the symbols: in my example the first symbol is %d, therefore the first value in the array must be an integer; the second symbol is %.0f, and the second value must be a float (1000.0/INTERVALS[..]). If the Format function would not be used the string could also be created in the traditional way as
Code: Pascal  [Select][+][-]
  1.   Label1.caption := 'Interval ' + IntToStr(INTERVALS[Trackbar1.Position]) +
  2.                          ' ms --> ' + IntToStr(round(1000.0/INTERVALS[Trackbar1.Position]) + ' frames/s';

/3/ TrackbarChange in FormCreate

This is simple initialization work: I want the timer to have the interval associated with the Trackbar.Position set up by the Object Inspector, and I want the label to display the associated numbers. This is exactly what is done by the Trackbar's OnChange handler, and that's why I call it. The event handler requires a Sender parameter which normally is the Trackbar. But since the Sender is not used by the current code I simply typed "nil" - a bit dirty, I agree...


pascal111

  • Sr. Member
  • ****
  • Posts: 423
  • Un trabajo en equipo para programas serias.
Re: Frame rate in "TGifAnim" object
« Reply #8 on: May 06, 2021, 07:45:51 pm »
/1/ INTERVALS array

When you scroll the Trackbar its Position property varies between its Min and Max values - they are 0 and 5 in this example. I am using the INTERVALS array to prepare an interval value for the timer for each step of the Trackbar. When the trackbar is at the left (Position = 0) the Timer.Interval becomes INTERVALS[0] = 1000, the longest interval, i.e. very slow rendering. Or when the trackbar is at the right (Position =5) then the Timer.Interval becomes 10 ms, the shortest interval, i.e. very fast renderung. Spending more typing work and probably requiring a bit more memory you could achieve the same effect by
Code: Pascal  [Select][+][-]
  1. case TrackBar1.Position of
  2.   0: Timer1.Interval := 1000;
  3.   1: Timer1.Interval := 300;
  4.   2: Timer1.Interval := 100;
  5.   3: Timer1.Interval := 40;
  6.   4: Timer1.Interval := 20;
  7.   5: Timer1.Interval := 10;
  8. end;


It means you understand what you're doing to the extent in which you can express the same technique in other various ways, you do understand programming techniques. I have gotten benefits from your code and explinations.

/2/ Format function

Yes, this function probably has the spirit of C in mind, but it is extremely useful. It has two arguments: the format mask string, and the argument list. The mask string contains symbol such as %s or %d, and they are replaced by the corresponding values from the argument list which is given as an array. %s is replaced by a string, %d is replaced by an integer value, %f by a floating point value (in this latter case the count of decimal places is given by the number before the "f" - "%.0f" means: "show the float with 0 decimals"). You must be careful to provide the value list in the same order as the symbols: in my example the first symbol is %d, therefore the first value in the array must be an integer; the second symbol is %.0f, and the second value must be a float (1000.0/INTERVALS[..]). If the Format function would not be used the string could also be created in the traditional way as
Code: Pascal  [Select][+][-]
  1.   Label1.caption := 'Interval ' + IntToStr(INTERVALS[Trackbar1.Position]) +
  2.                          ' ms --> ' + IntToStr(round(1000.0/INTERVALS[Trackbar1.Position]) + ' frames/s';


Pascal being able to do the same task with more than one way means that it is a rich language. It's using the logical vertical thinking in unique ways. This is important for the intellectual skills and treating the poorness of limited vertical low thinking.

/3/ TrackbarChange in FormCreate

This is simple initialization work: I want the timer to have the interval associated with the Trackbar.Position set up by the Object Inspector, and I want the label to display the associated numbers. This is exactly what is done by the Trackbar's OnChange handler, and that's why I call it. The event handler requires a Sender parameter which normally is the Trackbar. But since the Sender is not used by the current code I simply typed "nil" - a bit dirty, I agree...

I think you mean that this 1st call in "FormCreate" considered as a first click and to adjust the running of the animated image with the pre-modified property "Position = 3" at the design time, and - of course - the sender will be "nil" because there is no real component called the event. It's sensible.

There's nothing dirty in what you made, all what you made is intelligent, and your project can be considered formal educational one. You are real Pascal programmer.
La chose par la chose est rappelé.

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: Frame rate in "TGifAnim" object
« Reply #9 on: May 06, 2021, 07:56:00 pm »
/2/ Format function

Yes, this function probably has the spirit of C in mind, but it is extremely useful. [... etc ...]

Maybe a pointer to the documentation wouldn't be amis? ;)
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: Frame rate in "TGifAnim" object
« Reply #10 on: May 06, 2021, 08:02:44 pm »
the sender will be "nil" because there is no real component called the event. It's sensible.
I think this is too much of interpretation because the OnChange handler of the trackbar could have been written in a more general way like this:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.TrackBar1Change(Sender: TObject);
  2. const
  3.   INTERVALS: array[0..5] of Integer = (1000, 300, 100, 40, 20, 10);
  4. var
  5.   trackbar: TTrackbar;
  6. begin
  7.   trackbar := Sender as TTrackbar;
  8.   Timer1.Interval := INTERVALS[trackbar.Position];
  9.   Label1.Caption := Format('Interval %d ms --> %.0f frames/s', [
  10.     INTERVALS[trackbar.Position],
  11.     1000.0/INTERVALS[trackbar.Position]
  12.   ]);
  13. end;
While the old code refered to the trackbar instance on the form (Trackbar1) the new code takes the Sender parameter, checks whether it really is a TTrackbar ("Sender as TTrackbar") and then uses it. This technique is very common when there are several Trackbars on the form and they all share the same OnChange handler.

In this case my "TrackbarChange(nil)" on the form's OnCreate handler would crash because the Sender now is nil, but not a TTrackbar! The correct way here would be to call "TrackbarChange(Trackbar1)" even if Trackbar1 has not been clicked physically.

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: Frame rate in "TGifAnim" object
« Reply #11 on: May 06, 2021, 08:04:12 pm »
/2/ Format function

Yes, this function probably has the spirit of C in mind, but it is extremely useful. [... etc ...]

Maybe a pointer to the documentation wouldn't be amis? ;)
Of course. I lost myself in typing... But I think sometimes it is good when beginners read a well-documented topic in different words.

pascal111

  • Sr. Member
  • ****
  • Posts: 423
  • Un trabajo en equipo para programas serias.
Re: Frame rate in "TGifAnim" object
« Reply #12 on: May 06, 2021, 08:44:48 pm »
/2/ Format function

Yes, this function probably has the spirit of C in mind, but it is extremely useful. [... etc ...]

Maybe a pointer to the documentation wouldn't be amis? ;)

I think this function is well documented with details, and although that its documenting is readable more than C++ functions. Pascal has the same power of C++ but they differs in their styles, I think C++ treats high programming tools in low level programming manner by mean that you see direct functions or procedures in Pascal like "str" or "val" have the sensible number of arguments, but in C++ the equivalents are using more details like modifiers, its style isn't the directs way of using high level tools, it tends to be low level or something like that while Pascal have the tools of high programming style, so those are familiar with high programming in languages like BASIC find advanced high level features in Pascal, but in C++ the situation differs than that.

It's powerful point that Lazarus freePascal is well documented and have effective community, it's learnable while I didn't find effective support for C++, it becomes more obscure.
La chose par la chose est rappelé.

pascal111

  • Sr. Member
  • ****
  • Posts: 423
  • Un trabajo en equipo para programas serias.
Re: Frame rate in "TGifAnim" object
« Reply #13 on: May 06, 2021, 10:39:33 pm »
the sender will be "nil" because there is no real component called the event. It's sensible.
I think this is too much of interpretation because the OnChange handler of the trackbar could have been written in a more general way like this:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.TrackBar1Change(Sender: TObject);
  2. const
  3.   INTERVALS: array[0..5] of Integer = (1000, 300, 100, 40, 20, 10);
  4. var
  5.   trackbar: TTrackbar;
  6. begin
  7.   trackbar := Sender as TTrackbar;
  8.   Timer1.Interval := INTERVALS[trackbar.Position];
  9.   Label1.Caption := Format('Interval %d ms --> %.0f frames/s', [
  10.     INTERVALS[trackbar.Position],
  11.     1000.0/INTERVALS[trackbar.Position]
  12.   ]);
  13. end;
While the old code refered to the trackbar instance on the form (Trackbar1) the new code takes the Sender parameter, checks whether it really is a TTrackbar ("Sender as TTrackbar") and then uses it. This technique is very common when there are several Trackbars on the form and they all share the same OnChange handler.

In this case my "TrackbarChange(nil)" on the form's OnCreate handler would crash because the Sender now is nil, but not a TTrackbar! The correct way here would be to call "TrackbarChange(Trackbar1)" even if Trackbar1 has not been clicked physically.

I think this point is related to event driven programming or OOP of the new structure of Pascal in freePascal. Is there a documentation has details about points like you mentioned about events, senders ... etc
La chose par la chose est rappelé.

wp

  • Hero Member
  • *****
  • Posts: 11853
Re: Frame rate in "TGifAnim" object [SOLVED]
« Reply #14 on: May 06, 2021, 10:44:58 pm »
Google for "sender lazarus". One of the first items found is this nice article by Zarko Gajic: https://www.thoughtco.com/understanding-sender-parameter-in-delphi-event-handlers-1058223 (but they have awful code formatting on this page...)

 

TinyPortal © 2005-2018