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.
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?
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 5 years ago.
Improve this question
I developed application that transfer bytes via virtual serial port using Delphi 6 and asyncfree
I need to delay transfer after 10 bytes to synchronize transmission. I use windows.sleep(1).
The application works very well when I run it from Delphi IDE. When I close Delphi and run application from exe ... the application becomes slow.
What is the reason?
The Delphi IDE obviously sets the system timer tick to a higher resolution. You can do the same in your application by using timeBeginPeriod/timeEndPeriod functions. See msdn document and also this one regarding sleep function
uses MMSystem;
if TimeBeginPeriod(1) = TIMERR_NOERROR then // 1 ms resolution
try
// The action or process needing higher resolution
finally
TimeEndPeriod(1);
end;
Just to demonstrate the effect I made following simple application, so anybody interested can check for themselves:
uses System.DateUtils, MMSystem;
var
s, e: TTime;
procedure SomeDelay;
var
i: integer;
begin
s := Now;
for i := 1 to 1000 do
Sleep(1);
e := Now;
end;
procedure TForm19.btnWithClick(Sender: TObject);
begin
if TimeBeginPeriod(1) = TIMERR_NOERROR then // 1 ms resolution
try
SomeDelay; // The action or process needing higher resolution
finally
TimeEndPeriod(1);
end;
Memo1.Lines.Add('with ' + IntToStr(SecondsBetween(s, e)));
end;
procedure TForm19.btnWithoutClick(Sender: TObject);
begin
SomeDelay; // The action or process needing higher resolution
Memo1.Lines.Add('without ' + IntToStr(SecondsBetween(s, e)));
end;
Output:
with 1
without 15
NOTE Because the TimeBeginPeriod affects the system tick, be sure to shut down any program that may us the same method to modify the timer tick, like multimedia and similar programs (and also the Delphi IDE).
Currently in my application the user is able to create windows (no controls on the as of yet) which are docked to a pagecontrol. Each editor has a set of toolboxes associated with them. This set is reset upon editor construction and modified as toolboxes are closed and opened. When the page control changes tab the state of the toolboxes is saved, they are closed and then the toolboxes for the new tab are restored.
My application is crashing (seemingly randomly at first) when you change tab. I believe it is when you change tab very fast (the speed of a double click) the processing of the toolboxes in the PageControl.OnChange event doesnt complete before the next PageControl.OnChange event starts and I end up with two events running in 'parallel'. My questions are:
1) Does this sound like a plausible theory? I am aware there is a GUI processing thread does delphi work by dispatching new threads to deal with events?
2) How would you suggest going about fixing this? Hold the messages until the first method finishes (it is a very quick method so there shouldnt be any use lag really)?
Here is some code incase anyone would like to look at the problem from another angle.
This is the code for the onchange event.
procedure TMainForm.PageDockingAreaChange(Sender: TObject);
var
count : integer;
// Shortcut variables
FormShortcut : TForm;
WelcomeShortcut : TWelcomePageForm;
BaseEditorShortcut : TBaseEditor;
begin
// Set nil values
FormShortcut := nil;
WelcomeShortcut := nil;
BaseEditorShortcut := nil;
// Create shortcut value
FormShortcut := Self.GetActiveForm;
if (FormShortcut is TWelcomePageForm) then WelcomeShortcut := TWelcomePageForm(FormShortcut);
if (FormShortcut is TBaseEditor) then BaseEditorShortcut := TBaseEditor(FormShortcut);
// Hide all tabs when welcome page is visible
if (WelcomeShortcut <> nil) then
begin
// Clear any existing toolboxes
Self.ToolboxClearAll;
end;
{endif}
// Try to execute toolbox setup
try
// Load toolbox state
Self.ToolboxSetup(BaseEditorShortcut);
except
// Display fatal error to the user
ShowMessage('Fatal Error : Unable to load toolboxes.');
end;
// Update last active editor
if (BaseEditorShortcut = nil) then
Self.LastActiveEditor := nil
else
Self.LastActiveEditor := BaseEditorShortcut;
{endif}
end;
This method closes all toolboxes and frees them in turn.
procedure TMainForm.ToolboxClearAll;
var
count : integer;
begin
// Save toolbox state if needed
if Assigned(Self.LastActiveEditor) then
Self.LastActiveEditor.SaveToolboxState;
// Close and free all toolboxes
for count := 0 to length(Self.ActiveToolboxes)-1 do
Self.ToolboxCloseAndFree(Self.ActiveToolboxes[count]);
// Reset array size (should already be done though)
SetLength(Self.ActiveToolboxes, 0);
end;
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.
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.