In Praise of All Things Idle
by
, 26-Apr-2010 at 08:00 AM (3478 Views)
Recent research has suggested that "devil" is actually an old fashioned spelling for "developer". While this does not entirely surprise me, I will leave the theological implication of this to others. What I would like to discuss is how this applies to the old adage "Idle hands are the devil’s workshop". Does this really refer to developers and, if so, how can we make idle hands or, more accurately idle handlers part of our workshop?
In Visual DataFlex revision 12.1, we introduced the cIdleHandler class. We added this so we’d have an easier way to enable and disable our new toolbar menu items. If you were not paying close attention to our "What’s New" section you might have missed this new class and, even if you had read about this class, you might not have paid much attention to it. It’s time to pay attention as this is a really useful class.
What does an Idle Handler object do?
The cIdleHandler is a single purpose class with a simple interface. When enabled, it sends itself the message OnIdle whenever your application is about to go idle. An application is idle, when it is waiting in a loop for user input (mouse or keyboard) and there is nothing to process. Right before your application goes into this waiting mode, the OnIdle event is sent. Because this is fired when your application has nothing to do, this is a good time to tell it to perform various housekeeping tasks. Because this is only fired once, it is efficient.
The idle handler only sends OnIdle events when it is enabled. The idle handler can be enabled and disabled at the appropriate times by setting its pbEnabled property. Normally, you will enable and disable this object when its parent object is activated and deactivated. You can do this in the parent object's Activating and Deactivating events. Here’s an example of using an idle timer in a dbView.
If you run this you will see that the application is easily bored. If you want it to stop complaining, you need to treat it like a child. Either keep it busy or pay no attention to it at all.Code:Object oIdleView is a dbView Set Border_Style to Border_Thick Set Size to 200 300 Set Location to 2 2 Object oIdleHandler is a cIdleHandler Procedure OnIdle Showln "I’m bored!" End_Procedure End_Object Procedure Activating Forward Send Activating Set pbEnabled of oIdleHandler to True End_Procedure Procedure Deactivating Set pbEnabled of oIdleHandler to False Forward Send Deactivating End_Procedure End_Object
How would you use an Idle Handler?
Idle handlers are particularly useful for visually enabling and disabling parts of your views. For example you may have an Ok button in a view that should only be enabled when you have all of the information needed to proceed. There are two ways to you could do this. One approach is to find every place in your view where an action may change the Ok button’s status and send a message enabling or disabling that button. Finding all those places can be rather difficult. The other approach is to use an idle handler that will set the button’s status when it has nothing better to do. That’s the approach we want.
Notice that the oIdleHandler object delegates OnIdle to the parent. This is typical.Code:Object oIdleView is a dbView Set Border_Style to Border_Thick Set Size to 200 300 Set Location to 2 2 Object oButton1 is a Button Set Location to 174 237 Set Label to 'Ok' // fires when the button is clicked Procedure OnClick Send Ok End_Procedure Object oIdleHandler is a cIdleHandler Procedure OnIdle Delegate Send OnIdle End_Procedure End_Object Procedure Activating Forward Send Activating Set pbEnabled of oIdleHandler to True End_Procedure Procedure Deactivating Set pbEnabled of oIdleHandler to False Forward Send Deactivating End_Procedure Procedure OnIdle Boolean bIsValid Get IsStuffInMyViewValid to bIsValid Set Enabled_State to bIsValid End_Procedure Function IsStuffInMyViewValid Returns Boolean Function_Return (Random(2)) // I’ve copyrighted this test End_Function End_Object End_Object
While you could add an idle handler to every control in your view that requires dynamic enabling and disabling, you can also create a single handler in your view, which will act as the central controller for this activity. Often this is the desired approach. For example, you could change the order entry view so that it does the following:
- Enables the Print button when there is an order to print.
- Enables a Save button in the order header section when a header section save is required.
- Disables the Order Detail grid when the header needs saving or when there is no header record at all.
Here is the code you’d want to add to your view object to do this:
As you can see, this type of approach is easy to code and easy to extend. It also provides a very windows-like solution where the enabling and disabling of controls gives your users the guidance they need. Prior to the introduction of the cIdleHandler implementing this could be pretty difficult. Now it’s so simple you might actually find yourself with idle time on your hands.Code:Object oIdle is a cIdleHandler Procedure OnIdle Delegate Send OnIdle End_Procedure End_Object Procedure Activating Forward Send Activating Set pbEnabled of oIdle to True End_Procedure Procedure Deactivating Set pbEnabled of oIdle to False Forward Send Deactivating End_Procedure Procedure OnIdle Boolean bChanged bRec Handle hoServer Get Server to hoServer Get Should_Save of hoServer to bChanged Get HasRecord of hoServer to bRec Set Enabled_State of oSaveHdrButton to bChanged Set Enabled_State of oOrderDtl_Grid to (not(bChanged) and bRec) Set Enabled_State of oPrintBtn to bRec End_Procedure