i was wondering if anyone could by any chance help me. i have a school project due in 10 days and to be honest i have no idea what im doing =/ what is expected of me is that i program a memory game. where i am currently stuck is that i have to time how long it takes the person to play the game and then display how long it took them as a 'score' at the end. how do i time? what component should i use and how do i program this component to time? it should start when a button is clicked and then end when the game finnishes. any help will be highly appreciated!
Why don't you save the current time in a variable when he starts the game, and again save the time when he ends?
You can take it by the Now instruction.
var time: TDateTime;
begin
time := now;
ShowMessage(DateTimeToStr(time));
end;
You'll see the current time in the system.
You will need
1.- In your form,
add a timer, and set its Enabled property to False.
add a label to display the time
add a private attribute startTime to record the time when the user starts the game.
should result something like this...
type
TForm1 = class(TForm)
...
Label1: TLabel;
Timer1: TTimer;
...
private
startTime:TDateTime;
....
2.- At the click event of the start button, the code to initialize the startTime attribute and kick-off the Timer.
procedure TForm1.Button1Click(Sender: TObject);
begin
startTime:=Now;
Timer1.Enabled:=True;
....
end;
3.- At the Timer event of the Timer, some code to display the time counting
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Label1.Caption:=TimeToStr(Now-startTime);
....
end;
4.- At the click event of the finish button, or when the program considers the end of the game, some code to stop the timer.
procedure TForm1.Button2Click(Sender: TObject);
begin
Timer1.Enabled:=False;
Label1.Caption:=TimeToStr(now-startTime);
....
end;
PA's answer seems to be exactly what you need. because if i understood well and this is your first time working with delphi, i'd only add that:
Now is a function defined in SysUtils that returns the current date&time
you'll find the TTimer on the System component pallette (see image in link below)
all the procedures where you need to write the code will be automatically generated by selecting the Events tab in the Object inspector, and then double clicking in the input box (see image in link below)
http://i.stack.imgur.com/0iNsL.png (sorry, can't inline images because i don't have the necessary reputation yet)
from here on it hould be very easy to finish your application
good luck,
G
Create a variable (for example StartTime) of TDateTime type in your form.
When the user starts playing, set the variable to equal Now().
When the user finishes, calculate the value of Now()-StartTime. The result is a decimal number that represents the fraction of a day that elapsed between the starting time and ending time.
To convert that to the number of seconds, multiply it by (60 * 60 * 24) (which is the number of seconds in a day). From there you can display the number however you want.
Related
I am using a TEdit to allow the user to enter a number, e.g. 10.
I convert the TEdit.Text to an integer and a calculation procedure is called.
In this calc procedure, a check was built-in to make sure no numbers below 10 are processed.
Currently I use the OnChange event. Suppose the user wants to change '10' into e.g.'50'. But as soon as the '10' is deleted or the '5' (to be followed by the 0) is typed, I trigger my warning that the minimum number is 10. I.e. the program won't wait until I have fully typed the 5 and 0.
I tried OnEnter, OnClick, OnExit, but I seem not to overcome this problem. The only solution is to add a separate button that will trigger the calculation with the new number. It works, but can I do without the button?
Use a timer for a delayed check, e.g.:
procedure TForm1.Edit1Change(Sender: TObject);
begin
// reset the timer
Timer1.Enabled := false;
Timer1.Enabled := true;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
Timer1.Enabled := false;
// do your check here
end;
Setting the timer to 500 ms should be fine for most users.
And as David suggested in the comments to the question: Do not show an error dialog, use something less intrusive instead, e.g. an error message in a label near the edit or change the background color. And also: Do not prevent the focus to be moved away from that control and do not play a sound, that's also very annoying.
For our in house software we set the background of a control to yellow if there is an error and display the error message of the first such error in the status bar and also as a hint of the control. If you do that, you probably don't even need to have the delay.
Thanks, for your help. I tried the timer option, but could not get that to work. I now have this code, which works (almost - see below), but requires the used to always type a CR:
procedure Calculate;
begin
// this is my calculation procedure
ShowMessage('calculation running correctly');
end;
procedure TForm1.Edit1KeyPress(Sender: TObject; var Key: Char);
var
N : integer;
begin
if Key = #13 then
begin
N := StrtoInt(Edit1.Text);
if N<10 then ShowMessage('<10!') else
if N>100 then ShowMessage('>100!') else Calculate;
end;
end;
I used the ShowMessage() here only to see if the sample code worked. In the real program I have left that out, as you all suggested.
I also included the 'turn yellow on wrong entry' (thanks David). The only issue is that if the user runs this I get a beep from my computer. I can't see what went wrong. But what is causing the beep?
I am trying to use a timer to check the the timestamp of the file to check if it has been modified, if this is true it must add the line from the text file to a richedit. The problem is that it continually adds the line to the richedit every 1/4 second (timer interval). I have tried different methods but can't get it right.
procedure TForm1.Timer1Timer(Sender: TObject);
Var
Filet : textfile;
filename, readtxt : string;
filedate1, filedate2 : integer;
begin
assignfile(filet, 'S:\share.talk');
filename := 'S:\share.talk';
filedate1 := FileAge(filename);
if filedate1 <> filedate2 then begin
reset(filet);
readln(filet, readtxt);
richedit1.lines.add(readtxt);
closefile(filet);
filedate2 := filedate1;
end;//if
end;
thanks for all help.
In your code
if filedate1 <> filedate2 then begin
reset(filet);
readln(filet, readtxt);
richedit1.lines.add(readtxt);
closefile(filet);
filedate2 := filedate1;
end;
the comparison between filedate and filedate2 assumes that these retain their values between calls to Timer1Timer. They do not, because they are declared local to Timer1Timer and are therefore 'forgotten' between calls because they are stored on the stack.
To get them to retain their values, remove the declaration on them local to Timer1Timer and declare them as fields of TForm1 instead.
Btw, be aware that with this design, you are going to run into other issues, like how to handle concurrent access to the network textfile, etc, but they are not related to the specific point you asked about.
The problem it that you are openning and closing file every time the timer ticks.Open the file on TForm1.FormCreate by a TFileStream with fmOpenReadWrite or fmOpenShareDenyNone parameters, close it on TForm1.FormDestroy, and read it on TForm1.Timer1Timer if the number of read bytes are greater than zero convert the buffer to string and add it to the richedit.
This is because everytime you are resetting the filedate1 and filedate2 when the procedure runs. A better way to implement this function is to return the lastwrite time from the procedure and call the procedure on timer with the lastwrite time that was returned to you. Then you can compare the current time and the last time and do the refresh. On the first loop pass the current time and then keep using the lastread time in all subsequent calls and the result of which will keep updating the lastread time.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
i am develop a small mobile application in XE5 using delphi, i will show the current location in google map in webbrowser. the problem is how to refresh the google map every x minutes in webbrowser. the default refresh time is 20 second. thanks.
Use TTimer to refresh.
You can change the X minutes in the property Interval.
procedure TForm1.FormCreate(Sender: TObject);
begin
self.WebBrowser1.Navigate('www.embarcadero.com');
self.Timer1.Interval:= 10000;
self.Timer1.Enabled:= True;
end;
procedure TForm1.Timer1Timer(Sender: TObject);
begin
self.WebBrowser1.Refresh;
end;
# Tom Brunberg
I use the Locationsensor LocationChange to display the google map in WebBrowser,below is the code:
procedure TTabbedForm.LocationSensor1LocationChanged(Sender: TObject;
const OldLocation, NewLocation: TLocationCoord2D);
const
LGoogleMapsURL: String = 'https://maps.google.com/maps?q=%s,%s&';
begin
ListBoxItem3.Text := 'Latitude: ' + NewLocation.Latitude.ToString;
ListBoxItem2.Text := 'Longitude: ' + NewLocation.Longitude.ToString;
Locationsensor1.Distance:=200;
{ and track the location via Google Maps }
WebBrowser1.Navigate(Format(LGoogleMapsURL, [NewLocation.Latitude.ToString, NewLocation.Longitude.ToString]));
// Timer1.Interval:=50000;
// Timer1.Enabled:=true;
ClientModule1.ServerMethods19Client.insertParcelLocation(EDIT4.Text,now,NewLocation.Longitude,NewLocation.Latitude);
i want to refresh the google map in webBrowser every 5 minutes.Thus, i use the TTimer. but i do not know where to raise Timer event? the code below is i try to raise the timer event in webBrowser, but it did not work!
procedure TTabbedForm.Timer1Timer(Sender: TObject);
const
LGoogleMapsURL: String = 'https://maps.google.com/maps?q=%s,%s&';
begin
WebBrowser1.Navigate(Format(LGoogleMapsURL,[Locationsensor1.Sensor.Latitude.ToString,LocationSensor1.Sensor.Longitude.ToString ]));
Timer1.Interval:=50000;
Timer1.Enabled:=true;
end;
Presumably you are navigating with something like
WebBrowser1.Navigate('https://www.google.com/maps/#<latitude>,<longitude>,<zoom>z');
and you want to update the map because the location has changed.
In this case there's no point in calling something like refresh (on TWebBrowser for Windows, or similar on TWebBrowser for mobile), since that would just use the same coordinates as before.
Instead, at the timer event, get your updated location and then simply navigate as above with the new coordinates.
Edit after new info
Right now I can not verify with a real LocationSensor so I assume that the LocationSensor and the request for the initial map works in the OnLocationChanged event. Note also that depending on installed technology in your device, the location sensor may need quite some time to be ready to report location changes.
You attempt to initialize (set interval and enable) the timer in the OnLocationChanged event, (except that now those lines are outcommented). Thus starting the timer depends of course on this event to fire. If you have verified that the OnLocationChanged event fires then this is OK, just take away the comment markers.
However, if initially, the OnLocationChanged event doesn't fire, then you need to start the timer somewhere else. When you drop a TTimer on a form, it is by default enabled and has an interval of 1000 ms. So you could just change the interval to 5 minutes (300 000 ms) at design time and the timer will start at program startup.
On the other hand, you may want to show the (or a) google map immediately in which case you could use the OnShow event of the form, using a previously saved (or default) location until the LocationSensor starts to report location changes.
// Instead of having this constant in several procedures,
// place it for example in the private section of your form
const
LGoogleMapsURL: String = 'https://maps.google.com/maps?q=%s,%s&';
var
SavedLocation: TLocationCoord2D;
....
procedure TTabbedForm.FormShow(Sender: TObject);
begin
// using a previously saved location
WebBrowser1.Navigate(Format(LGoogleMapsURL,
[SavedLocation.Latitude.ToString, SavedLocation.Longitude.ToString]));
// remove these lines if timer is enabled at design time
Timer1.Interval := 300000;
Timer1.Enabled := true;
end;
You don't need to repeatedly set the timer interval and enabled properties in the OnTimer event
procedure TTabbedForm.Timer1Timer(Sender: TObject);
const
LGoogleMapsURL: String = 'https://maps.google.com/maps?q=%s,%s&';
begin
WebBrowser1.Navigate(Format(LGoogleMapsURL,[Locationsensor1.Sensor.Latitude.ToString,LocationSensor1.Sensor.Longitude.ToString ]));
// you can remove these two lines
// Timer1.Interval:=50000;
// Timer1.Enabled:=true;
end;
If this doesn't answer your question, you need to be more specific in how you want it to work and what precisly is not as you want.
Edit 2
Next time you really need to describe all aspects of your problem.
The OnLocationChanged event is an event of LocationSensor1. The easiest way to get rid of it is to remove from LocationSesnor1LocationChanged any const and var declaration as well as the code between begin and end. Then just do a build and the IDE will remove all traces of it.
I need to show a message say "Hi" everyday at 9 AM. Do I require Timer for this? How can I check whether its 9 AM or not. What should be the interval of timer at which OnTimer event run?
procedure Form1.TimerTimer1(Sender: TObject);
begin
ShowMessage("Hi");
end;
If I run this event in after 24 hours, I fear it might pass 9 AM and will not fire.
Unless you have other valid reasons, it's far more easier to
write a simple application that shows the message and quits
schedule it to run using the task scheduler of Windows
You can use CRON like solutions for Delphi: http://www.cromis.net/blog/downloads/cron-scheduler/
As the answerers before me said, there are better and easier ways. Suppose you want to do this your way, in Delphi, then yes, you need a timer. The needed steps are:
Put the timer on your form;
Set the "interval" property to 1000 (one second) or less. For greater precision, you can set the interval property to 1, and the program will do the checking each milisecond
Write the handler for OnTimer:
procedure Form1.TimerTimer1(Sender: TObject);
var x:TDateTime
begin
x:=Now;
if {the hour read is 9 and minute is 0} then
ShowMessage("Hi");
end;
Hope it helps.
Is it possible to determine when a TTimer in Delphi will trigger? I know how to calculate this based upon the timer's last run and the timers interval. Unfortunately, the code I am working with has many states and the interval can change in many ways. I would prefer to not have to keep track of when the timer was last enabled and the interval changed, but instead directly access this information from the timer.
Scenario: A timer has a 2 minute interval, 30 seconds have elapsed since it was last enabled, how do I find out in code that in 90 seconds the timer event will trigger again?
Is it possible to get this information from the timer directly? Or perhaps the OS? The timer component must "know" when it will be triggered next. How does it know? Is this information I can access?
There's absolutely no way to query a Windows timer for information of this nature. You will simply have to keep track of this yourself.
I would do this by wrapping up the TTimer with composition and not inheritance. You can then be sure that you will capture all modifications to the timer state.
In this case I recommend you switch from a TTimer which uses Windows timers, to a thread based TTimer-style component. Then you can query the time until the next event.
Alternative; If you want a simple ugly hack, then change your Timer interval to 1 second instead of 120 seconds, and do a countdown yourself:
const
CounterPreset = 120;
...
procedure TForm1.FormCreate(Sender:TObject);
begin
FCounter := CounterPreset;
Timer1.Interval := 1000;
Timer1.Enabled := true;
end;
procedure TForm1.Timer1Timer(Sender);
begin
Dec(FCounter);
if (FCounter<=0) then
begin
DoRealTimerCodeHere;
FCounter := CounterPreset;
end;
end;
function TForm1.TimeLeft:Integer;
begin
result := FCounter;
end;
This will be inaccurate subject to the limitations of the WM_TIMER message, documented only vaguely at MSDN here. Real experience shows that WM_TIMER should only be used for things that don't need to happen at all, and should be used as a convenience, not as a hard-timing system.