A TamsPalm reader recently brought up an interesting point to me:
“As for VersaMail, well I think this unresponsive cancel button is going to put me over the top.”
Why is it that in many applications cancel buttons JUST DON’T WORK? Contrary to popular belief, this is not the fault of the developer. It is actually one of the side effects of event driven programming. Consider the following diagram as that of a typical application. (simplified of course):
In this application a cancel button would be pointless. When a user presses the cancel button an event is placed in a queue. All of the events in the queue before it must be processed before the application realises that the cancel button has been pressed. By then it is too late and the action the user wanted cancel has already been completed.
A complex application like VersaMail adds a bit to this design:
In this application we hit a problem: We are out of the event loop! So what? Well, hitting the cancel button queues an event, but the event queue is not been processed in the send mail loop. So, the loop will not terminate until all of the mails are sent!
How Can I Create a Working Cancel Button?
There are a few ways that I can reason.
1) Process nilEvents
Most developers don’t realize how helpful nilEvents really are. By using nilEvent to handle repitive tasks (such as sending or recieving multiple emails) you can keep your UI active.
The first thing that you have to do is make sure that you are actually getting nilEvent. Most applications use EvtGetEvent(&event, evtWaitForever); but this will keep you from getting nilEvent. You must change the second parameter to a suitable number, say, EvtGetEvent(&event, SysTicksPerSecond()); which is saying if there are no events after one second, send me a nilEvent.
Once this is done, add nilEvent handling to your form’s event handler so that it does one piece of your repetive task, and you are set!
2) Create a background thread
Contrary to popular belief, there is at least one (:-)) public API for multithreading: the sound stream API allows you to create a secondary thread. IMHO, you cannot call any UI functions in the thread, but you CAN place you sendmail routine into this seperate thread and use feature memory for the two threads to communicate.
While creating a background thread may seem a bit hackish, it works well for large tasks.
So, if your application has a large or repitive set of tasks that keeps the cancel button from working, consider implementing one of the above options. It will make for a better user experience in the end.