Recent

Author Topic: [SOLVED]Adapting this code to use TFloatSpinEdit?  (Read 3029 times)

Lampbert

  • New Member
  • *
  • Posts: 33
[SOLVED]Adapting this code to use TFloatSpinEdit?
« on: January 29, 2020, 01:54:45 pm »
Hello,

My program creates a TTimer and the user enters into TEdit a value in seconds and presses TButton and the value in seconds is counted down in [hh:nn:ss] and displayed on TLabel. Here is the code:

Code: Pascal  [Select][+][-]
  1. unit Unit1;
  2.  
  3. {$mode objfpc}{$H+}
  4.  
  5. interface
  6.  
  7. uses
  8.   Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, ExtCtrls,
  9.   DateUtils;
  10.  
  11. type
  12.  
  13.   { TForm1 }
  14.  
  15.   TForm1 = class(TForm)
  16.     Button1: TButton;
  17.     Edit1: TEdit;
  18.     Label1: TLabel;
  19.     procedure Button1Click(Sender: TObject);
  20.     procedure CreateTimerNormal;
  21.     procedure timCountdownTimer(Sender: TObject);
  22.   private
  23.  
  24.   public
  25.  
  26.   end;
  27.  
  28. var
  29.   Form1: TForm1;
  30.   TimeOut: TDateTime;
  31.   NewTimer: TTimer;
  32.  
  33. implementation
  34.  
  35. {$R *.lfm}
  36.  
  37. { TForm1 }
  38.  
  39. procedure TForm1.CreateTimerNormal;
  40. begin
  41.   if not Assigned(NewTimer) then begin
  42.     NewTimer := TTimer.Create(Self);
  43.     with NewTimer do
  44.     begin
  45.       Interval := 1000;
  46.       OnTimer := @timCountdownTimer;
  47.       Enabled := False;
  48.     end;
  49.   end;
  50. end;
  51.  
  52. function SecsToHmsStr(ASecs: integer):string;
  53. begin
  54.   Result := Format('%2d:%2.2d:%2.2d',
  55.     [ASecs div 3600, ASecs mod 3600 div 60, ASecs mod 3600 mod 60]);
  56. ;end;
  57.  
  58. procedure TForm1.timCountdownTimer(Sender: TObject);
  59. begin
  60.   Label1.Caption := SecsToHmsStr(SecondsBetween(Now, TimeOut));
  61.   if Now > Timeout then NewTimer.Enabled := False;
  62. end;
  63.  
  64. procedure TForm1.Button1Click(Sender: TObject);
  65. var
  66.   Seconds: integer;
  67. begin
  68.   CreateTimerNormal;
  69.   if TryStrToInt(Edit1.Text, Seconds) then
  70.   begin
  71.     TimeOut := IncSecond(Now, Seconds);
  72.     NewTimer.Enabled := True;
  73.     Label1.Caption := SecsToHmsStr(SecondsBetween(Now, TimeOut));
  74.   end
  75.   else
  76.     ShowMessage('Error in number of seconds');
  77. end;
  78.  
  79. end.

How can I, instead of using a TEdit where the user inputs the number of seconds, use a TFloatSpinEdit where the user enters the number of hours and minutes [hh:nn], and it will count down in the same way as before?

[EDIT]: The user enters into TFloatSpinEdit the number of hours; so, for example, 6.5 would make the TTimer count down from 6 hours and 30 minutes.
« Last Edit: February 26, 2020, 11:51:52 am by Lampbert »

Bart

  • Hero Member
  • *****
  • Posts: 3939
    • Bart en Mariska's Webstek
Re: Adapting this code to use TFloatSpinEdit?
« Reply #1 on: January 29, 2020, 02:19:53 pm »
A TFloatSpinEdit can hold only floating point numbers, so how is the user supposed to enter both hours and minutes then?

You can of cousse always hack the system by setting DecimalSeparator to ':' and then use Trunc() and Frac() on the Value property, but this is not going to work on GTK2 at least.
TFloatSpinEditEx has a DecimalSeparator proerty, so there this hack will work.

Feel free to abuse this control in such a way.
The up-down arrows will however the spin up the value from e.g. 12:59 to 12:60, possibly not what you want (and users still can input such invalid times).

Consider using TDateTimeControls.
Alternatively use a TMaskEdit and filter out invalid time in it's OnChange event.

Or use my TTimeEdit component (you must create it at runtime, there's no design time package yet) which handles most of that for you by ways of the ForceValidTimeOnChange and ForceValidTimeOnExit properties.

Bart

Lampbert

  • New Member
  • *
  • Posts: 33
Re: Adapting this code to use TFloatSpinEdit?
« Reply #2 on: January 29, 2020, 02:24:34 pm »
Hi Bart, it's my mistakes, sorry - I meant that the user would enter the number of hours in the TFloatSpinEdit, so, for example, 6.5 would make the TTimer count down from 6:30:00 (hh:nn:ss).

Bart

  • Hero Member
  • *****
  • Posts: 3939
    • Bart en Mariska's Webstek
Re: Adapting this code to use TFloatSpinEdit?
« Reply #3 on: January 29, 2020, 03:48:26 pm »
That would be no problem at all.
1 day as a TDateTime = 1.0 as a Double.
The Value of the TFloatSpinedit is hours, so simply divide by 24.

Bart

lucamar

  • Hero Member
  • *****
  • Posts: 3074
Re: Adapting this code to use TFloatSpinEdit?
« Reply #4 on: January 29, 2020, 05:02:31 pm »
What you want is to convert a number of hours to seconds which can be easily done with either:
Code: Pascal  [Select][+][-]
  1. Seconds := Trunc(FloatSpinEdit1.Value * 3600);
or:
Code: Pascal  [Select][+][-]
  1. Seconds := Round(FloatSpinEdit1.Value * 3600);

Either of them should do the trick nicely. :)

Your Button1.OnClick handler should then be something like:

Code: Pascal  [Select][+][-]
  1. procedure TMainForm.Button1Click(Sender: TObject);
  2. const Minimum = 1; {Minimum seconds for it to be worth the effort}
  3. var
  4.   Seconds: integer;
  5. begin
  6.   CreateTimerNormal;
  7.   Seconds := Trunc(FloatSpinEdit1.Value * 3600);
  8.   if Seconds > Minimum then
  9.   begin
  10.     TimeOut := IncSecond(Now, Seconds);
  11.     NewTimer.Enabled := True;
  12.     Label1.Caption := SecsToHmsStr(SecondsBetween(Now, TimeOut));
  13.   end
  14.   else
  15.     ShowMessage('Error in number of seconds');
  16. end;

ETA: A note about your SecsToHmsStr - You would get the same result using:
Code: Pascal  [Select][+][-]
  1. Label1.Caption := FormatDateTime('tt', TimeOut - Now);

HTH!
« Last Edit: January 29, 2020, 05:35:40 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.8/FPC 3.0.4 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Lampbert

  • New Member
  • *
  • Posts: 33
Re: Adapting this code to use TFloatSpinEdit?
« Reply #5 on: January 29, 2020, 05:51:16 pm »
What you want is to convert a number of hours to seconds which can be easily done with either:
Code: Pascal  [Select][+][-]
  1. Seconds := Trunc(FloatSpinEdit1.Value * 3600);
or:
Code: Pascal  [Select][+][-]
  1. Seconds := Round(FloatSpinEdit1.Value * 3600);

Either of them should do the trick nicely. :)

Your Button1.OnClick handler should then be something like:

Code: Pascal  [Select][+][-]
  1. procedure TMainForm.Button1Click(Sender: TObject);
  2. const Minimum = 1; {Minimum seconds for it to be worth the effort}
  3. var
  4.   Seconds: integer;
  5. begin
  6.   CreateTimerNormal;
  7.   Seconds := Trunc(FloatSpinEdit1.Value * 3600);
  8.   if Seconds > Minimum then
  9.   begin
  10.     TimeOut := IncSecond(Now, Seconds);
  11.     NewTimer.Enabled := True;
  12.     Label1.Caption := SecsToHmsStr(SecondsBetween(Now, TimeOut));
  13.   end
  14.   else
  15.     ShowMessage('Error in number of seconds');
  16. end;

ETA: A note about your SecsToHmsStr - You would get the same result using:
Code: Pascal  [Select][+][-]
  1. Label1.Caption := FormatDateTime('tt', TimeOut - Now);

HTH!

Many, many, many thanks for that - my problem is now 100% resolved. Thanks you lucamar

lucamar

  • Hero Member
  • *****
  • Posts: 3074
Re: Adapting this code to use TFloatSpinEdit?
« Reply #6 on: January 29, 2020, 06:02:06 pm »
Glad to be of help :)
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.8/FPC 3.0.4 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Lampbert

  • New Member
  • *
  • Posts: 33
Re: Adapting this code to use TFloatSpinEdit?
« Reply #7 on: January 29, 2020, 10:45:24 pm »
Hi again,

I'm trying to get that countdown to display in a TStringGrid cell when the cell is created at runtime, instead of Label1.Caption, but I can't get the time to update, it just stays still.

Code: Pascal  [Select][+][-]
  1.   StringGrid1.InsertRowWithValues(StringGrid1.RowCount + 0,
  2.     [A]); // Where 'A: String' is 'SecsToHmsStr(SecondsBetween(Now, TimeOut))'


Obviously here, the program enters the String into the StringGrid, but the timer isn't told about the cell that's created at runtime and therefore cannot reference it. How would I be able to reference that cell so that the countdown happens in that cell?

Thanks.

winni

  • Hero Member
  • *****
  • Posts: 1894
Re: Adapting this code to use TFloatSpinEdit?
« Reply #8 on: January 29, 2020, 11:49:30 pm »
Hi!

That code works without problems.

So: Is string 'A' not empty? Add a sign to string for testing.

What is the interval of the timer? If it is to fast it may be that there is not enough time inbetween two tics to display the row.
Insert after the stringGrid.InsertRow......   a

Application.ProcessMessages

to handle all waiting events.

Winni

Lampbert

  • New Member
  • *
  • Posts: 33
Re: Adapting this code to use TFloatSpinEdit?
« Reply #9 on: January 30, 2020, 01:09:56 pm »
Hi winni,

My code does not work without problems. Please see the attached project and you will see that, while Label1.Caption is updated and counted down every second, the StringGrid1 cell containing 'a' is not.

Thank you.

lucamar

  • Hero Member
  • *****
  • Posts: 3074
Re: Adapting this code to use TFloatSpinEdit?
« Reply #10 on: January 30, 2020, 01:40:00 pm »
Since you're using InsertRowWithValues() you already know the row/column where A is shown so an obvious way to keep track of it for update is to store the position in some global variable (or form field) which can then be used to access the proper StringGrid.Cells[] in the OnTimer event handler.

It's difficult to say more without seeing your code and what the intention is, sorry. Didn't see your posted project :-[
I'll give a look when (if) I find some free time.

ETA: OK, here is your project with some small modifications to implement the above idea. HTH!
« Last Edit: January 30, 2020, 01:57:23 pm by lucamar »
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.8/FPC 3.0.4 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Lampbert

  • New Member
  • *
  • Posts: 33
Re: Adapting this code to use TFloatSpinEdit?
« Reply #11 on: January 31, 2020, 05:55:00 pm »
Thanks again for your help lucamar, that solves the problem.

Lampbert

  • New Member
  • *
  • Posts: 33
Re: Adapting this code to use TFloatSpinEdit?
« Reply #12 on: February 02, 2020, 04:11:44 pm »
I'm now trying to add multiple countdowns to the StringGrid that will all continue to count down to zero, instead of just one countdown at a time.

From some research, I found that all TComponents have the Tag property where you can store a value with a TComponent. Since I'm trying to create multiple timers at runtime, I figured this would be a good way to reference them.

Bear in mind also that the user can both add and remove rows in the StringGrid.

Should I be able to do it with:
Code: Pascal  [Select][+][-]
  1. NewTimer.Tag := StringGrid1.Row;

Or is there a better way to do it that doesn't involve Tag - can a single TTimer run multiple countdowns?

See attached the project. Thanks.

lucamar

  • Hero Member
  • *****
  • Posts: 3074
Re: Adapting this code to use TFloatSpinEdit?
« Reply #13 on: February 02, 2020, 05:17:57 pm »
You can do that but what I would probably do is use an array or TObjectList or similar class to store the timers in such a way that I could access the timer and the grid row with the same index.

Using the Tag of the timer would mean that each time a row is inserted/deleted you would have to traverse all the timers to adjust the number of the linked row, which might have changed. Not impossible but tedious and bug-prone.
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus 2.0.8/FPC 3.0.4 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

Lampbert

  • New Member
  • *
  • Posts: 33
Re: Adapting this code to use TFloatSpinEdit?
« Reply #14 on: February 02, 2020, 05:38:49 pm »
Cheers lucamar, having a look at the wiki, TObjectList looks like the way to go for sure. Will see if I can figure out how to use it now.

 

TinyPortal © 2005-2018