Why implement a countdown timer

When performing a task that will take some time it is useful to show how long it has taken, and how long to go. In this section we will implement a countdown timer so that Sudokus can be solved ‘against the clock’. If you want to implement a more general countdown timer, look here.

Avoiding ‘Microsoft time’

I’m sure you have all suffered from that installation problem where it says its 50% complete, suddenly jumps to 97% complete then starts again. This is particularly common with Microsoft applications – hence the term ‘Microsoft Time’. In addition, a timer is quite often implemented as part of a loop of a process. However, in this case, since we are going to mainly be waiting for input, we wont have a processing loop to use, so we have to implement an asynchronous approach to updating our timer.

What’s needed?

We are going to need a couple of things
  • A label that will change color and size as the countdown progresses, and a textbox showing how many seconds are left.
  • The capability to schedule an update that resizes and recolors the label and updates the textbox.
  • A couple of controls to pause and restart the timer.

I’ve chosen to implement a class called cSudProgressBar to take care of these requirements, and to add a few controls to our form. This gives us this result – you can see the progress bar at the bottom, and I change the amount of time allowed depending on the calculated difficulty of the Sudoku. As usual the complete code and project is available in the download section.

Code and explanation

  • For timing, i’m using the cMicroTimer function which I implemented as part of the optimization package.
  • For scheduling updates, i’m using Application.ontime – this schedules the next time that the progress bar needs updating. There are some quirks about application.ontime

Application.ontime is a method of the global application object. Its function is to schedule an upcoming event in a particular period of time. The application object is provided by Excel as an abbreviation which does not need to be prefixed by the global object to which Application belongs. The problem is that if multiple instances of Excel are running, it can become disconnected ans screw up. Luckily I found this Microsoft explanation that helped me to figure out to fix that problem. This led me to calling application.ontime with a prefix identifying the specific application object , which i have previously initialized in cSudPuzzle as follows. Set pxlApp = GetObject(, “Excel.Application”).

One of the arguments for application.ontime is the name of the procedure that should run when the schedule time arrives (in this case the contents of pScheduleUpdateProcess). The strangeness here is that you cannot implement the called procedure as part of a class. It has to be a ‘normal procedure’. Since I wanted to encapsulate all this in the cSudProgressBar class, we need a workaround. In this case, I initialize the class, passing to it the name of a ‘normal procedure’ that will know which class method to call. This name is stored in pScheduleUpdateProcess so it can be passed to application.Ontime. All that progressupdate does is to call the appropriate method. The key is to make sure it is a public procedure of a ‘normal module’
  • The progress bar itself is an msforms.Label, whose length is shortened according to the %age of time that has passed. It will also change color as time runs out.
The complete code is below, or can be downloaded as part of the Sudoku Project.
 
cSudProgressBar class
For help and more information join our forum, follow the blog or follow me on twitter