This section describes ObjectPak's support for busy states. A busy state is when you lock out user input during an operation.
Entering and Exiting Busy States Using ViewKit ObjectPak
Whenever you expect a procedure to take considerable time to complete, you can call the VkApp::busy() function before entering the relevant region of code to lock out user input in all application windows:
If you call busy() with no arguments, the application simply displays a busy cursor. If you provide a string as the first argument, the application posts a dialog to display the string. The string is treated first as a resource name that busy() looks up relative to the dialog widget. If the resource exists, its value is used as the message. If the resource does not exist, or if the string contains spaces or newline characters, busy() uses the string itself as the message.
If you provide a VkSimpleWindow (or subclass) as the second argument, the application posts the dialog over this specified window. If you do not specify a window, the application posts the dialog over the main window. (See "Managing Top-Level Windows" for instructions on setting the main window. See Chapter 7--Using Dialogs for more details on dialog behavior.)
The VkApp::notBusy() function undoes the previous call to busy():
virtual void notBusy()
You can nest calls to busy(), but you must always have matching busy()/notBusy() pairs. An application exits the busy state only when the number of notBusy() calls matches the number of busy() calls.
Note: ViewKit ObjectPak does not "stack" nested busy dialogs, it simply displays the most recently posted busy dialog. Once you post a busy dialog, it remains displayed until the busy state is over or you replace it with another busy dialog.
Example 13. shows an example of setting busy dialog messages using resource values and using nested busy()/notBusy() calls. Note that this is not a complete example: it lists only the code relating to the busy states.
Example 13. Using Busy States in a ViewKit ObjectPak Application
Code
- class ReportWindow: public VkSimpleWindow {
- public:
- ReportWindow ( const char *name );
- ~ReportWindow();
- virtual const char* className();
- void report();
- void sort();
- private:
- static String _defaultResources[];
- };
- String _defaultResources[] = {
- "*sortDialogMsg: Sorting records...",
- "*reportDialogMsg: Generating report...",
- NULL
- };
- ReportWindow::ReportWindow(const char *name) : VkSimpleWindow ( name )
- {
- setDefaultResources(theApplication->baseWidget(), _defaultResources);
- // Create window...
- }
- void ReportWindow::sort()
- {
- theApplication->busy("sortDialogMsg");
- // Sort records...
- theApplication->notBusy();
- }
- void ReportWindow::report()
- {
- theApplication->busy("reportDialogMsg");
- // Report generation...
- sort();
- // Report generation continued...
- theApplication->notBusy();
- }
The ReportWindow class defines the busy dialog messages as resource values and loads these values using setDefaultResources() in the ReportWindow constructor.1 The calls to busy() pass these resource names instead of passing the actual dialog text. This allows you to override these resource values in an app-defaults file should you need to.
When the application calls ReportWindow::report(), it posts the busy dialog shown in Figure 7.
Figure 7. Example of Busy Dialog
When the application calls ReportWindow::sort(), it posts the busy dialog shown in Figure 8.
Figure 8. Example of Nested Busy Dialog
Note: The application continues to display the second busy dialog until reaching the theApplication->notBusy() statement in ReportWindow::report().
Animating the Busy Cursor
To animate the busy cursor during a busy state, periodically call VkApp::progressing():
virtual void progressing(const char *msg = NULL)
If you have an animated busy cursor installed, progressing() cycles to the next Pixmap in the cursor list. If you have a fixed cursor installed, progressing() has no effect on the busy cursor.
If you provide a character string argument, your application posts a dialog to display the message. The string is treated first as a resource name that progressing() looks up relative to the dialog widget. If the resource exists, its value is used as the message. If the resource does not exist, or if the string contains spaces or newline characters, progressing() uses the string itself as the message.
The code fragment in Example 14. performs a simulated lengthy task and periodically cycles the busy cursor.
Example 14. Animating the Busy Cursor
Code
- int i;
- // Start being "busy"
- theApplication->busy("Busy", (BusyWindow *) clientData);
- for(i=0; i<100; i++)
- {
- // Every so often, update the busy cursor
- theApplication->progressing();
- sleep(1);
- }
- // Task done, so we"re not busy anymore
- theApplication->notBusy();
Installing Different Busy Dialogs
By default, busy() displays the dialog using theBusyDialog, a global pointer to an instantiation of the VkBusyDialog class2 (described in "Busy Dialog" ). If you prefer to use a different dialog object, you can pass a pointer to the object to the setBusyDialog() function:
void setBusyDialog(VkBusyDialog *dialog)
This alternate busy dialog must be implemented as a subclass of VkBusyDialog. Calling setBusyDialog() with a NULL argument restores the default VkBusyDialog object.
Most frequently, you will use setBusyDialog() to install theInterruptDialog, a global pointer to an instantiation of the VkInterruptDialog class, which implements an interruptible busy dialog3. ("Interruptible Busy Dialog" describes the VkInterruptDialog class.) Example 15. shows how to temporarily install an interruptible busy dialog for a task.
Example 15. Temporarily Installing an Interruptible Busy Dialog
- #inlcude <Vk/VkApp.h>
- #include <Vk/VkInterruptDialog.h>
- // ...
- // Install theInterruptDialog as the busy dialog
- theApplication->setBusyDialog(theInterruptDialog);
- theApplication->busy("Generating report"); // Enter busy state
- // Perform task...
- theApplication->notBusy(); // Exit busy state
- theApplication->setBusyDialog(NULL); // Install default busy dialog