Tek-Tips is the largest IT community on the Internet today!

Members share and learn making Tek-Tips Forums the best source of peer-reviewed technical information on the Internet!

  • Congratulations Mike Lewis on being selected by the Tek-Tips community for having the most helpful posts in the forums last week. Way to Go!

Timer in VFP6 3

Status
Not open for further replies.
An interesting question, Keith.

One possibility would be to add a custom property to the timer class which stores the actual datetime at which the timer starts. You could perhaps do that in the Enabled property's Assign method.

Then, to find how long the timer has to run, subtract the start time from the current time. That will tell you how long it's been running for so far. Then subtract that from the value in the Interval property to tell you how long it's still got to run.

The whole thing could be made generic, by putting it in your base timer class.

No doubt there are other methods too.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips, training, consultancy
 
Mike gave the solution that I would normally use myself. But if for some reason that solution is not to your liking you could do this.

Create 2 timers one that runs say at 1/10 ( or 1/100 or whatever ) of the other. The 'sub' timer can run and when it 'fires' it shouts out that 1/10th of the time has passed and 90% remains, 80% remains etc. So in effect it is not an exact time left, but a semi-regular countdown.

OH BTW assuming that the timer is running for times less then a day and not over midnight then I would make one change from Mike's suggestion, that is to use seconds() and store as an integer, not using a datetime. This is a programmers preference kind of thing, the use of datetime is not wrong, nor is seconds right, I just find seconds/integers much easier to deal with in these kinds of situations. DateTime is much better for LONG running timmers (Over 24 hours )thou!

Lion Crest Software Services
Anthony L. Testi
President
 
Thanks for both of those suggestions.
The 2 timers solution sounds good as I can create a sountdown slider bar which will help the users.
With regards datetime() vs. seconds() my preference is always seconds() in Foxpro. It is much easier to manipulate several numbers and then do the pretty formatting at the end of the calcs and. Even better, in other languages I use are the old fashioned epoch seconds (the number of seconds since 1971).



Keith
 
Just a warning about the timing of timer events. Setting Interval to 1000 does not mean a timer event exaclty every 1000 ms.

I've recently helped someone in the german dfpug newsgroups, who did a timer for a stop clock. Setting Interval to 1 he thought he could count ms in a counter in the timer event and once arriving at 1000 this would be 1 second. There was a mismatch though, in that he had 1064 events during one second, so even more events than planned.

The VFP Timer is not very accurate.

I tend to work with Disabling the timer during the timer event, calling Timer.Reset() and setting Enabled = .T. at the end. This way it doesn't matter how long the event takes and I always have a interval during which the Timer() explicitly NOT runs.

Of course this is not the only way to handle a timer, but it has paid for me in the past. Even if you don't do so, you don't get a timer event, while the timer event still runs. This code demonstrates this non reentrant behavior of the VFP Timer:

Code:
Public oTimer
Declare Integer Sleep in Win32API integer milliseconds
oTimer = CreateObject("testtimer")
Define Class testtimer as timer
   Interval = 500
   Enabled = .T.
   Procedure Timer()
      ? Seconds()
      Sleep(1000)
      Doevents Force
   Endproc
EndDefine

This displays seconds() only about once per second due to the Sleep, even though the Timer Interval is 500 ms, so you would expect two outputs per second.

And in other words: This also means there is no limit to fear, you can take longer within the Timer() event, than the timer interval is, you just don't get the number of events expected per overal Time since the Timer started.

You better synchronize via Seconds() or Datetime() or another Timer if the time is of relevance.

If you need the next Timer Event at a specific time you better individually set the Timer.Interval within the Timer.Timer() event and call Timer.Reset() right before ending the event. But even then you can't expct the next timer interval to occur at the planned time.

Timers are for roughly having an event every Interval milliseconds, no more, no less.

Bye, Olaf.
 
Keith,

Anthony's suggestion looks good. Personally, I think I would use my own idea, mainly because I could implement it in my base timer class and then forget about it. But that's just my personal preference.

Regarding the use of "seconds since midnight": Back in Foxbase days, before we had timers, I needed to perform a certain process for exactly two seconds. To do so, I used the SECONDS() function to trap the number of seconds since midnight, and then kept testing it again until the difference was two seconds.

One night, I couldn't sleep, and started thinking about work. I suddenly thought - what would happen if the process started less than two seconds before midnight? SECONDS() would click back to zero before it had a chance finish, and it would never come out of its loop.

I swear I went straight to the office the next morning and modified the code to take account of that. It was ridiculous, given that the users never worked later than about 6 pm. But it pained me to think that there was a bug lurking in the code.

I wonder if I would do the same thing today.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips, training, consultancy
 
Fortunately, accuracy is not an issue in this instance.
It is set to create and upload a stock level file to a web server every 2 hours or so. It wouldn't matter if it missed an entire upload.

Keith
 
Mike,
Well that is 2 votes for your suggestion (Yours and my vote ) But I wanted to give options to AudioPro.

You are so right about the midnight assumption that is why I noted it in my posting

Every 2 hours send a file. Be carefull with this. I inheritted some code that was to upload files (multiple files) every so often. The code would send the first file, then because the time had changed did not bother to send the other files. e.g. the programmer said "The code requirements said to send any files at 2:00 am" it was 2:01 am so the code should not be sending any remaining files, I am not responsible for slow transfer times. The code meets the specifications. ( Note there became 100s of files waiting to be sent! )

I am glad I never met that programmer in person, it would have been a bad scene!

Lion Crest Software Services
Anthony L. Testi
President
 
BTW: Olaf.
I gave you a star for your good posting. I had forgoted about the timer being an aprox timer. Well should I say I have not used it for exact timing events, but it is good to be reminded of it. Thanks for taking the time to post the comment.

Lion Crest Software Services
Anthony L. Testi
President
 
Fortunately, accuracy is not an issue in this instance.
It is set to create and upload a stock level file to a web server every 2 hours or so. It wouldn't matter if it missed an entire upload.

Just to be the contrarian, I wouldn't use a timer for this.

I'd make a standalone exe that has one job: upload the necessary file(s). I'd launch that exe from Windows Task Scheduler. This is the kind of thing it's *for*, and it's good at it. <g>
 
I needed the value of the timer countdown mainly for testing purposes but now a working version of the auto uploader has been tested in anger, the design has had to be altered.

Accuracy is not important with this app but that is not to say that there are not other issues to complicate matters.
The app is a shop till which creates and uploads a data file to sync stock levels on their web server every 2 hours but only while the till is in use (no point sending up the same file all night while the shop is closed).

The first line of the file is the seconds() value when the file is created and this value is checked against the current seconds() value each time a sale is completed. If the abs difference between the 2 values is greater than 7200 a 10 second timer is enabled and a warning appears on screen to tell the operator that the stock will be updated shortly and a 10 sec. count down takes place. If the operator is still using the till, they press a button in the warning panel which cancels the 10 second countdown and cancels the upload until after the current transaction. This can be repeated until the till is unused, when the 10 second timer event triggers and the upload takes place.

This has to be better than their old method of manually uploading the file

Keith
 
Windows Task Scheduler. This is the kind of thing it's *for*, and it's good at it
Oh you naughty contrarian you :)

A previous version used that method but if someone was in the middle of a till transaction when task scheduler kicked in, both the shop assistant and the customer were left twiddling their thumbs while the file was processed. As we all know at such times, a 10 second process takes 2 hours and is almost as annoying as my work computer where 'System Idle Processing tasks' kick in while I am using the computer.
How do I tell the computer it is not idle!

Keith
 
a 10 second timer is enabled and a warning appears on screen to tell the operator that the stock will be updated shortly and a 10 sec. count down takes place."

In this situation a timer is very plausible and the accurracy to the ms wouldn't matter.

But before Dan's contra you only told about synching every two hours and for that the task scheduler would be good.

Bye, Olaf.
 
In a very similar case I used a timer to warn users before kicking them out of an application to be able to maintain the database (pack, reindex, backup, fixing errors etc.).

A Timer runs and checks for a maintainance flag every 5 minutes. If it detects such a flag it warns the user, the application is about to close automatic and asks to finish work. There is a second warning after 2 minutes and if users don't react to this or are not at the workstation, eg left the app and the computer running, the app closes.

You need to program in a way that prevents any modal state though, and need forms to revert any buffers and rollback any transactions in a cleanup process eg in forms QueryUnload.

In your case it's not necessary to shut the app down, just functions changing data, nevertheless it's quite similar. I don't see though, why you would need to read out how much time is left until the next timer event.

If I'd want to display a countdown during the 2 mintues between the first and 2nd warning, then I could simply initially set the interval to 5 minutes, let the timer event to look out for a flag and in case this flag is set, then set a countdown and lower the interval to 1000ms, the following events then count down, in the end starting the shut down process. So the timer simply has two modes. Some idle mode, only checking with very low frequency and an active mode, displaying the alert and countdown to the user.

Bye, Olaf.
 
A previous version used that method but if someone was in the middle of a till transaction when task scheduler kicked in, both the shop assistant and the customer were left twiddling their thumbs while the file was processed.

Only if you write it that way. [shadeshappy] There's no reason this kind of operation needs to have any sort of visual presence at all, much less be an interruption -- unless you choose to do it that way.
 
Dan
So it is possible to do this as a background task - that would be much better but when I run it as a separate program, it appears to lock the table until it has finished creating the file.

This is what locks the user out if they are in the middle of a transaction.

Keith
 
Keith,

it appears to lock the table until it has finished creating the file.

Then you need to find out why it is locking the table, and do something about it.

It could be that EXCLUSIVE is ON (sorry if this is stating the obvious), or that you have SET LOCK ON and are using one of the commands that automatically lock the table, or some other similar cause.

Mike

__________________________________
Mike Lewis (Edinburgh, Scotland)

Visual FoxPro articles, tips, training, consultancy
 
I agree with Mike,

what ever "it" is that creates the stock level file you mentioned earlier that's used for synching.

If you need a table as a source for creating some file to send over for synching, all you need is read access.

What can lock you out of a dbf besides automatic lock, which are mostly limited to the time you write changes, is of course manual locking, which depends on your usage of locks. Using a table exclusive would also be obviously locking another process out. Also a transaction limits access to dbfs, even read access.

If you already start a transaction when users begin editing data, then you're not using transactions the way they are intended.

As a sample:
Code:
* vfp started twice

* in one vfp session do
BEGIN TRANSACTION
USE some.dbf
APPPEND BLANK

* in the other vfp session simply try
Use some.dbf

* this will either fail or wait for access (depending on REPROCESS setting and also )

* in session one do
ROLLBACK

*at that moment the other vfp session gains access to the dbf

This is even true for EXCLUSIVE OFF, using DBFs shared. That's the effect of a transaction.

The recommeded way to keep transactions and their indirect locking short is to use buffering, buffered tables or better buffered cursoradapters cursors, view cursors etc, while users work on data and then only start the transaction before doing Tableupdate() for every table involved.

Besides, you only need to use a transaction, if more than one table is involved in a transactional update of the database, eg if two or more tables are related and only the full set of data saved leads to the next consistent database state, eg only saving a full order with all order positions/items in a shop system.

If you live by that, time slots, in which shared access isn't possible, are short - only limited to the time someone is saving. Some user having some form open then does not prevent you from reading the current consistent database state out to some file for synching another server. This synch will not include the change a user currently is working on, but who cares? it's not yet in the database at all.

Bye, Olaf.
 
Sorry if I am confusing the issue but my reference to a transaction refers to a shop transaction rather than a VFP transaction. It was quite a while ago when I set that up and had forgotten the exact circumstances.
When the original task scheduler invoked upload routine fired, all form controls became inaccessable while the stock file was created. The creation routine skipped through the stock list and added the relevant records to the stock file, which was then uploaded to the server. The lockout only lasted for a short time but it was annoying to the operator.
The latest automatic upload has been tested recently and the client is quite happy with it. The process is only interupted if the till is in use when the upload occurs.


Keith
 
Status
Not open for further replies.

Part and Inventory Search

Sponsor

Back
Top