Frame rate in "TGifAnim" object [SOLVED] lazarus / 39-Graphics ---------------------------------------------------------------------- pascal111 · 2021-05-06 11:51 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) ---------------------------------------------------------------------- wp · 2021-05-06 12:45 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. ---------------------------------------------------------------------- pascal111 · 2021-05-06 13:08 You are absolutely right! Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.Timer1Timer(Sender: TObject);begin   gifanim1.NextFrame;  Invalidate; end; ---------------------------------------------------------------------- wp · 2021-05-06 13:22 No need to "Invalidate" because the TGifAnim automatically repaints itself when the next frame is loaded: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TGifAnim.NextFrame;begin  if (not FEmpty) and Visible and (not FAnimate) then  begin    if FCurrentImage >= GifBitmaps.Count - 1 then      FCurrentImage := 0    else      Inc(FCurrentImage);    if Assigned(FOnFrameChanged) then      FOnFrameChanged(Self);    Repaint;     end;end; BTW, there's also a TGifAnim.PriorFrame. Following the same principle you can render an animation in reverse order. ---------------------------------------------------------------------- pascal111 · 2021-05-06 13:44 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  procedure TForm1.Button3Click(Sender: TObject);begin  gifanim1.PriorFrame;end; ---------------------------------------------------------------------- wp · 2021-05-06 14:33 Quote from: pascal111 on May 06, 2021, 03:44:58 pmFrom 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 Quote from: pascal111 on May 06, 2021, 03:44:58 pmI tried to use "TGifAnim.PriorFrame" to reverse the motion but it failed Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i  procedure TForm1.Button3Click(Sender: TObject);begin  gifanim1.PriorFrame;end;     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. ---------------------------------------------------------------------- pascal111 · 2021-05-06 15:45 I spent time to get the idea of this chunk of code: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.TrackBar1Change(Sender: TObject);const  INTERVALS: array[0..5] of Integer = (1000, 300, 100, 40, 20, 10);begin  Timer1.Interval := INTERVALS[Trackbar1.Position];  Label1.Caption := Format('Interval %d ms --> %.0f frames/s', [    INTERVALS[Trackbar1.Position],    1000.0/INTERVALS[Trackbar1.Position]  ]);end;       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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.FormCreate(Sender: TObject);begin  Trackbar1Change(nil);end; ---------------------------------------------------------------------- wp · 2021-05-06 16:40 /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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i case TrackBar1.Position of  0: Timer1.Interval := 1000;  1: Timer1.Interval := 300;  2: Timer1.Interval := 100;  3: Timer1.Interval := 40;  4: Timer1.Interval := 20;  5: Timer1.Interval := 10;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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   Label1.caption := 'Interval ' + IntToStr(INTERVALS[Trackbar1.Position]) +                          ' 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 · 2021-05-06 17:45 Quote from: wp 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i case TrackBar1.Position of  0: Timer1.Interval := 1000;  1: Timer1.Interval := 300;  2: Timer1.Interval := 100;  3: Timer1.Interval := 40;  4: Timer1.Interval := 20;  5: Timer1.Interval := 10;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. Quote from: wp on May 06, 2021, 06:40:41 pm/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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i   Label1.caption := 'Interval ' + IntToStr(INTERVALS[Trackbar1.Position]) +                          ' 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. Quote from: wp on May 06, 2021, 06:40:41 pm/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. ---------------------------------------------------------------------- lucamar · 2021-05-06 17:56 Quote from: wp on May 06, 2021, 06:40:41 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? ---------------------------------------------------------------------- wp · 2021-05-06 18:02 Quote from: pascal111 on May 06, 2021, 07:45:51 pmthe 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.TrackBar1Change(Sender: TObject);const  INTERVALS: array[0..5] of Integer = (1000, 300, 100, 40, 20, 10);var  trackbar: TTrackbar;begin  trackbar := Sender as TTrackbar;  Timer1.Interval := INTERVALS[trackbar.Position];  Label1.Caption := Format('Interval %d ms --> %.0f frames/s', [    INTERVALS[trackbar.Position],    1000.0/INTERVALS[trackbar.Position]  ]);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 · 2021-05-06 18:04 Quote from: lucamar on May 06, 2021, 07:56:00 pmQuote from: wp on May 06, 2021, 06:40:41 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 · 2021-05-06 18:44 Quote from: lucamar on May 06, 2021, 07:56:00 pmQuote from: wp on May 06, 2021, 06:40:41 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. ---------------------------------------------------------------------- pascal111 · 2021-05-06 20:39 Quote from: wp on May 06, 2021, 08:02:44 pmQuote from: pascal111 on May 06, 2021, 07:45:51 pmthe 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][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i procedure TForm1.TrackBar1Change(Sender: TObject);const  INTERVALS: array[0..5] of Integer = (1000, 300, 100, 40, 20, 10);var  trackbar: TTrackbar;begin  trackbar := Sender as TTrackbar;  Timer1.Interval := INTERVALS[trackbar.Position];  Label1.Caption := Format('Interval %d ms --> %.0f frames/s', [    INTERVALS[trackbar.Position],    1000.0/INTERVALS[trackbar.Position]  ]);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 ---------------------------------------------------------------------- wp · 2021-05-06 20:44 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...) ---------------------------------------------------------------------- pascal111 · 2021-05-06 20:50 Quote from: wp on May 06, 2021, 10:44:58 pmGoogle 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...) I didn't mean talking about "sender" particularly, I meant documents for architecture or construction of event driven programming in Lazarus or I'll gain that by learning classes and for example I'll see events there and how they are being built to understand the mechanism of programming in Lazarus. ---------------------------------------------------------------------- pascal111 · 2021-05-06 21:15 I found a book with google for Object Pascal, and found inside it a chapter talking about Classes, self, is and as operators, exceptions ... etc, so I think this is it the part I'm asking about, just add to it events and sender parameter and nil.