As mentioned in a previous post we added a new “dropdown-panel” dialog to the Database Toolpanel to allow the user to edit the viewing options:
Whilst this looked like a fairly simple job it did require a little bit of effort to get it right so we thought we’d share the method with you in case you wished to implement something similar in your own applications.
As this was dropdown panel we wanted it to behave as close as possible to the way that a dropdown list from a ComboBox works, i.e:
- It appears when a “parent button” is clicked
- It should appear underneath the parent button, right-justified
- The parent button should have a pressed appearance while the panel is displayed, and return to it’s normal state when the panel is closed
- The panel should close when it loses the focus (i.e. it becomes inactive)
- The Database Toolpanel is updated as each CheckBox is clicked, so there are no “OK” or “Cancel” buttons for this dialog.
So, this seemed to be a fairly straightforward task:
- On the Database Toolpanel:
- The parent button’s CheckStyle property was set to True so that it behaves like a CheckBox and stays pressed when clicked, and then unpressed when clicked again.
- A “SyncButton” OMNIEVENT handler was created for the Database Toolpanel that simply synchronizes the Check property of the button to True if the panel dialog exists, or False otherwise.
- On the panel dialog:
- The name of the parent button is passed to the dialog, and in the CREATE event it sets it’s own SYSTEMSIZE property relative to the SYSTEMSIZE of the parent button as required.
- The INACTIVATED event closes the dialog.
- When the dialog closes it posts the “SyncButton” OMNIEVENT to the Database Toolpanel
At first glance it appeared to work fine: the dialog appeared, you could update the view options, and when you clicked away from the panel it closed. Bravo.
The one remaining problem however, is that many users will click the parent button to close the dialog as well as open it – it’s just a natural action. In our case this actually had the effect of showing the dialog again, because the event sequence looked something like this (remember, by default all events in OpenInsight are executed asynchronously):
- The user clicks the mouse button (down) on the parent button
- The dialog deactivates and raises an INACTIVATED event
- The INACTIVATED event executes and closes the dialog, which in turn posts a “SyncButton” OMNIEVENT to the Database ToolPanel
- The “SyncButton” OMNIEVENT executes and, because the dialog no longer exists, it sets the parent button’s Check property to False
- The user releases the mouse button (up) on the parent button raising a CLICK event and setting the Check property to True
- The CLICK event executes and reloads the dialog again because the parent button’s Check property is True
To solve this we needed a way to jump into that sequence so we could set a flag to control how the synchronization logic behaves – we needed to stop it setting the parent button’s Check property to False if the user had clicked on it.
The solution was to use the parent button’s BUTTONDOWN event, because this runs after the INACTIVATED event, but before the OMNIEVENT, and before the mouse-up click changes the Check property. We made the following three changes:
- In the BUTTONDOWN handler we set a user-defined property (“@_BUTTONDOWN”) on the parent button to True. This is just to flag the fact that the button was clicked on by the user.
- In the “SyncButton” OMNIEVENT we check “@_BUTTONDOWN” – if it’s True then we don’t do anything else, otherwise we set parent button’s Check property to False (This means that if the user clicks away from the dialog it closes as normal).
- In the CLICK event we set “@_BUTTONDOWN” back to False, then look at the parent button’s Check property. If it’s False we don’t do anything, but if it’s True then we reload the dialog.
With these changes the dropdown panel dialog now behaves in a familiar fashion, and closes correctly regardless of how it loses the focus.