wait
wait
DELAY
,
SCOPE

The wait statement pauses the program for a specified period of time.

Parameters

This statement has two parameters:

delay – time to delay, in seconds. Must be an integer value. Zero is allowed and specifies the shortest possible delay.

scope – specifies whether the delay continues if the user clicks on a different window or database before the delay is finished. The possible options are global, database and window. The last two options may be modified with a suffix of background, for example windowbackground. If the scope is not specified, the default is database. See the text below for a detailed explanation of the scope options.

Description

This statement pauses the program for a specified period of time. After the delay, the program will resume operation right where it left off (usually, however there are some exceptions explained below, for example if the database was closed during the wait). Although the program containing the wait statement is paused, Panorama is not. Panorama remains fully operational during the wait period, and the user can do anything they want during that time – search, sort, edit data, open or close databases or windows, anything. When you use the wait statement, you must be careful that the code following the wait statement doesn’t assume that Panorama is in the same state it was in when the wait started.

Here is a simple program that simply waits for 30 seconds, then displays how long it waited.

    let start = now()
    wait 30
    message "Waited for "+now()-start+" seconds."

Note: The delay you specify is the minimum wait period. However, if Panorama is busy doing something else when the wait time is up, the delay will be extended until Panorama is finished with whatever it is doing. For example, if you specify a wait time of 30 seconds, you can’t count on the delay being 30 seconds, it could be 31, 32, 40 seconds, or even many minutes. But it will never be less than 30 seconds.

Note: If you want Panorama to delay for a specified period, but not allow other activity to take place during that period, use the delay statement instead of wait.

Warning: Do not use the wait statement in code that runs while a dialog is open. When a dialog window is open, the code following the wait statement will never execute.

### Using a Zero Second Delay

Paradoxically, the most practical use for the wait second is perhaps a zero second delay. This doesn’t actually mean no delay, instead, it means that Panorama will delay while Panorama is busy, then resume. Or, if you are executing code that isn’t running in the normal run loop (see Understanding the Run Loop), this gives you a chance to move the following code into a regular run loop. For example, code triggered by data entry (see Automatic Field Code) can’t normally add a record, because the normal run loop isn’t running when this code is triggered. So normally you can’t use the addrecord statement in this code (or any code that switches to a different database record). A simple solution is to insert `wait 0` at the top of the code, like this:

    wait 0
    addrecord

The code after the wait statement will not run until Panorama has finished up all of its tasks needed to tidy up data entry, and has gotten back to the regular run loop. At this point, the code can do pretty much anything it wants.

### Resuming after the Delay

When the wait is over, your code starts up again right where it left off. Your code doesn’t miss a beat, even all the local variables are just as you left them.

However, Panorama itself may be in a completely different state. During the wait, the user can have done anything - clicked on a different record, edited data, opened or closed windows, etc. Your code should check to see what state things are in before proceeding with its task.

#### Database Scope

Depending on the scope you assigned for the wait, there are some assumptions the code can make. If the scope is set to database (the default), you know for sure the database hasn’t changed. A different window in the database could be active, the data may have changed, but for sure the database will be the same as when the wait started.

What if you are using the database scope and the user clicks over to another database during the wait? If the user doesn’t click back, the wait will continue. In fact, the wait will continue until the user clicks back to the original database. When that happens, the wait will end immediately and your code will resume. In that situation the wait could be much longer than you specified.

If you don’t want to wait for the user to click back to the original database, specify the databasebackground scope.

    wait 30,"databasebackground"
    addrecord

With this option the code will resume immediately after 30 seconds, even if some other databaser is active. However, Panorama will create a “secret” window for the original database and make that active. So the code can rely on the original database being active, but not necessarily in a visible window.

What if you are using the database or databasebackground scope and the user closes the original database during the wait? In that case, the wait is cancelled and the code after the wait statement never runs.

#### Window Scope

If the scope is set to window, you know for sure the window hasn’t changed. The data may have changed, a different field or record may be active, but the same window is still active. What if you are using the window scope and the user clicks over to another window during the wait? If the user doesn’t click back, the wait will continue. In fact, the wait will continue until the user clicks back to the original window. When that happens, the wait will end immediately and your code will resume. In that situation the wait could be much longer than you specified. In fact, if the window was closed, the wait will be cancelled and the rest of the code will not run.

#### Global Scope

If the scope is set to global, all bets are off. You cannot make any assumptions about what window or database is active when the code resumes. However, that really doesn’t matter if all you want to do is display a message or perform some sort of global operation. This example displays a message in 5 minutes.

    wait 300,"global"
    message "Times up!"

Remember that since you don’t know what database you’ll wind up in, you can’t refer to anything in the current database. For example, a call statement might not work.

    wait 300,"global"
    call timesUp  // <-- this might not work

Instead, use the farcall statement.

    wait 300,"global"
    farcall "My Database",timesUp

Of course this still might not work, because My Database might have been closed during the wait (if the scope is global, the code continues even if the original database is closed.) If you want to be sure, check to make sure the database is open before calling.

### Multiple Waits

You’re not limited to one wait in a procedure, you could chain one after the other, like this:

    .. do something
    wait 5 // wait 5 seconds
    .. do something else
    wait 10 // wait 10 more seconds
    .. do a third thing

You could also use a loop to wait over and over, like this example that delays 2 seconds, three times in a row:

    let start = now()
    loop
       wait 2,"window"
       nsnotify now()-start
    until 3
    return

Note: You can get a similar effect using the starttimer function. Since wait actually uses starttimer internally, there is no real advantage to either method.

Suppose you set up a wait that is triggered by pressing a button. Press the button once, the wait starts. If the button is pressed again before the wait is up, the procedure will now be waiting twice. That’s ok, the two waits are completely independent. You can trigger the same wait over and over again, Panorama will keep it straight. If you don’t want that to happen, you’ll need to keep track of the fact that you’ve started a wait and block the request the second time.

See Also

- Automatic Field Code -- running a short program when data is entered into a field.
- changetimer -- modifies a repeating task that will be performed periodically when Panorama is not otherwise busy.
- delay -- loops for a specified period of time.
- endnoshow -- resumes the output of text and graphics after it has been disabled with the noshow statement.
- executeasap -- executes the specified code at the first possible opportunity, non-atomically.
- Implicitly Triggered Procedures -- Procedures that are triggered automatically when the user performs some normal Panorama action are said to be "implicitly triggered."
- info("computername") -- returns the name of the computer (as set up in the System Preferences Sharing panel).
- info("noshow") -- returns true if noshow is currently turned on, false if it is not.
- info("runningatomic") -- returns true if the current procedure is running as an "atomic" procedure.
- noshow -- temporarily disables the output of text and graphics.
- resumeaftertask -- resumes after a waitfortask statement.
- setwaitinglocal -- assigns a value to a local variable in the parent procedure of an asynchronous task, allowing the asynchronouse code to pass a value back to the code that spawned it.
- starttimer -- sets up and starts a repeating task that will be performed periodically when Panorama is not otherwise busy.
- Timer Workshop -- provides a tool for monitoring timers and testing timer configurations.
- timerexists( -- checks to see whether a timer exists.
- Timers -- executing recurring periodic background code at fixed intervals.
- Understanding the Run Loop -- explanation of how Panorama code interacts with the run loop to respond to mouse clicks, keyboard presses, display updates and other events that require attention.
- waitfortask -- temporarily pauses a procedure until the specified task is complete.

History

Version | Status | Notes
10.2 | New | New in this version.