Better message notifications in the Clarify Client
One of the common ways to do a message / notification to user from a from within the Clarify Classic Client is with a simple popup message box.
For example, if the user does a save operation on a form, and the save is successful, then it’s not uncommon to see a simple message box posted.
Sub btn_message_click()
App.MsgBox “Something Interesting Just Happened”
End Sub
These messages are purely informational. We’re not requiring the user to make a decision – we just want to tell them something.
The problem is that these message boxes interrupt the user’s flow.
Don’t interrupt my flow, man
Alan Cooper, in his book About Face 2.0, calls this stopping the proceedings with idiocy. And that’s exactly what it is.
There is a particular form of excise that is so prevalent it deserves special attention. In Chapter 9, we introduced the concept of flow, where the user enters a highly productive mental state by working in harmony with his tools. Flow is a natural state, and people will enter it without much prodding. It takes some effort to break into flow after someone has achieved it. Interruptions like a ringing telephone will do it, as will an error message box. Most interruptions are avoidable; a few aren’t. But interrupting a user’s flow for no good reason is stopping the proceedings with idiocyand is one of the most disruptive forms of excise.
Jeff Atwood expands on this: Unnecessary Dialogs: Stopping the Proceedings with Idiocy
It’s better on the web
On most good web sites, we don’t get these kind of popup messages – instead we’ll see a message as part of the page that gives the information, but doesn’t interrupt flow.
An example from Gmail, when an email is deleted:”
Improved Clarify messages
So lets look at accomplishing a similar type of non-invasive informational message within the Clarify Classic Client.
Here’s what it looks like.
I start with a simple form:
When I click the “Show a Message” button, the form shows an information message, on the form, without interrupting the user’s flow:
Implementation
This is actually pretty simple to do.
1. Add a new label to the form.
I’ve set its BackColor so that it stands out appropriately. I’ve also set the Visible property to false so that the label is initially invisible.
2. Add a little bit of ClearBasic code to set the message string, and make the label visible.
Sub btn_go_Click()
ShowMessage “Something Interesting Just Happened”
End SubSub ShowMessage (messageString As String)
lbl_message.caption = Space$(5) & messageString
lbl_message.Visible=True
End Sub
Upon clicking the button, my message shows:
In a web app, it’s easy to make that message go away after a few seconds. We can use a little jQuery to hide an element:
$("#message").hide();
And we can even use jQuery to fade it out, which is pretty sexy:
$("#message").fadeOut("slow");
In Clarify, we can hide the message after a few seconds:
Sub ShowMessage (messageString As String)
lbl_message.caption = Space$(5) & messageString
lbl_message.Visible=True
Sleep(3000)
Call HideMessage
End Sub
Sub HideMessage()
On Error Resume Next
lbl_message.caption = “”
lbl_message.Visible=False
End Sub
Notice that in the ShowMessage subroutine, I sleep for 3 seconds, and then hide the message by making it invisible.
What about a sexy fadeout?
Sorry – I haven’t solved that task yet. Maybe a task for another day.
Won’t the Sleep command block the user from doing other operations?
I thought that myself. But as it turns out, no. It doesn’t block. While that Sleep statement is happening, it blocks the current (ShowMessage) subroutine, but not other code.
So the user is free to do other things. Sweet!
But (there’s always a but) – if you open a modal dialog while that sleep is occurring (including a MessageBox), that will block other code from executing. When the modal dialog is dismissed, the other code can resume.
If your modal dialog has been opened for more than the Sleep time, then the next statement after the sleep will be immediately executed.
In my scenario, I can click the “Show a Message” button, which will show the message on the form. I then immediately click the “Show Message Box”, which opens a message box (App.MsgBox). While that MessageBox is posted, the message remains on the form. If I wait more than 3 seconds to close the MessageBox, then the message is hidden as soon as I dismiss the MessageBox.
Pretty nice!
What’s with the On Error Resume Next?
Notice that in the HideMessage subroutine, I’m doing an On Error Resume Next. This says, any messages that happen in this subroutine, just ignore.
The reason I’m doing this is to handle the following scenario:
- Display a message by calling ShowMessage
- Close the form before the Sleep time expires (within 3 seconds), while the message is still visible.
What will happen is that when the Sleep timer expires, the next line of code will be executed: lbl_message.caption = “”
Because the form is already closed, Clarify can’t find that label, so you get this lovely error message:
The given form for this operation is invalid (possibly already closed).
So, in order to workaround this, I’m just ignoring any error that results from hiding the message.
Niceties
We could sexy this up a bit by changing the background color of that message dynamically.
For example, if I want an informational message to be displayed in Yellow, but an error to be displayed in Red, then I could do that.
So an error message might look like:
To do this, we’ll create a new color scheme, and set the colors appropriately. Then we’ll call either ShowInfoMessage or ShowErrorMessage, which sets the colors appropriately before showing the message:
Sub CreateColorSchema()
Dim LabelList1 As New List
Dim ColorList1 As New List
LabelList1.AppendItem “ErrorBackground”, “ErrorForeground”, “InfoBackground”, “InfoForeground”
ColorList1.AppendItem “Red”, “White”, “Yellow”, “Black”
App.CreateColorScheme “messages”, LabelList1, ColorList1
End Sub
Sub Form_Load()
Me.Dodefault
Call CreateColorSchema
End Sub
Sub ShowMessage (messageString As String, level As String)
lbl_message.Visible=True
lbl_message.BackColor = level & “background”
lbl_message.ForeColor = level & “foreground”
lbl_message.caption = Space$(5) & messageString
Sleep(3000)
Call HideMessage
End Sub
Sub ShowErrorMessage (messageString As String)
ShowMessage messageString, “error”
End Sub
Sub ShowInfoMessage (messageString As String)
ShowMessage messageString, “info”
End Sub
Sub HideMessage()
On Error Resume Next
lbl_message.caption = “”
lbl_message.Visible=False
lbl_countdown.Visible = False
End Sub
Sub btn_info_Click()
ShowInfoMessage “Something Interesting Just Happened”
End Sub
Sub btn_error_Click()
ShowErrorMessage “An Error Happened”
End Sub
Summary
So there you have it – a better way to show informational and error messages to your users without interrupting their flow.
Hope you find this useful.