TaskTimer - An Object to Monitor Task Execution






4.38/5 (6 votes)
An object that tracks a task's elapsed and remaining times, and execution state
Introduction
This article describes TaskTimer
, a lightweight object that lets you easily track a task's elapsed and remaining times. Although there are various CodeProject articles that describe this functionality, this article separates the GUI aspect of progress display from the time computation. Because TaskTimer
isn't part of any control or dialog, you can make use of its functionality in any user interface. TaskTimer
also handles pausing and restarting the task being timed.
The sample application also demonstrates a couple of techniques that can help give your app a more professional look and feel:
- Making a single threaded app responsive while performing a long task
- Flicker free updating of progress text
How to Use TaskTimer
TaskTimer
is easy to use! First, declare an instance of the object in your dialog.
TaskTimer m_taskTimer; // TaskTimer object used for timing
When you want to start timing, call the object's start()
method.
// Start timing
m_taskTimer.start();
Every now and then, inform the object of your task's progress by calling its updateProgress()
method.
// Update the task progress
nProgress = ...;
m_taskTimer.updateProgress (nProgress);
To determine the task's elapsed and estimated remaining times, just call the appropriate methods.
// Get elapsed and remaining times
long nElapsedTimeInSecs = m_taskTimer.getElapsedTime();
long nRemainingTimeInSecs = m_taskTimer.getRemainingTime();
To display a user friendly time interval instead of the number of seconds, use the alternate form of these methods.
// Display user friendly remaining time
CString strRemaining;
m_taskTimer.getRemainingTime (strRemaining);
SetDlgItemText (IDC_TIME_REMAINING, strRemaining);
To indicate that the task has been paused, resumed or stopped, call the appropriate method.
// User pressed "Pause"
m_taskTimer.pause();
TaskTimer API
The TaskTimer
API contains functions to control timing, update progress, and retrieve timing and task state information.
// Control timing
void start(); // start timing
void pause(); // pause timing
void resume(); // resume timing
void stop(); // stop timing
// Update progress
void update(); // update elapsed time
void updateProgress // update progress
(long nProgress);
void updateProgress // update progress and get
(long nProgress, // remaining time
long& nRemainingTime);
// Retrieve timing
long getProgress(); // return current progress
long getElapsedTime(); // get elapsed time
void getElapsedTime // get elapsed time as components
(long& nHours,
long& nMinutes,
long& nSeconds);
void getElapsedTime // get elapsed time as formatted string
(CString& strElapsed);
long getRemainingTime(); // get remaining time
void getRemainingTime // get remaining time as components
(long& nHours,
long& nMinutes,
long& nSeconds);
void getRemainingTime // get remaining time as formatted string
(CString& strRemaining);
// Retrieve task state
bool isRunning(); // is task running?
bool isPaused(); // is task paused?
bool isStopped(); // is task stopped?
Responding to User Input While Performing a Long Task
To make a single threaded app respond to user input while performing a long task (e.g., within a pushbutton command handler), break up the task into a number subtasks and execute each subtask within a loop. After executing a subtask, pump the message queue. If you allow the user to cancel the task, check for cancellation after pumping the message queue, and take appropriate action.
void CTaskTimer_DemoDlg::OnStart()
{
// Start processing
m_taskTimer.start();
// For each of the 10 "subtasks" ...
for (long nTaskIterator=1; (nTaskIterator <= 10); nTaskIterator++) {
// Execute a subtask and update the task progress
doSomething();
m_taskTimer.updateProgress (nTaskIterator * 10);
// Pump the message queue
MSG msg;
while (::PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
AfxGetThread()->PumpMessage();
// Quit if user cancelled
if (m_bCancelled) {
m_taskTimer.stop();
break;
}
}
}
Flicker Free Updating of Progress Text
Although it's nice to provide your user with frequently updated progress information, constantly updating a static
text control can produce annoying flickering. This simple function shows how to do away with flicker by only setting the control's text if it's changed.
void updateWindowText
(CWnd* pWnd,
CString strText)
{
ASSERT (pWnd != NULL);
CString strOldText;
pWnd->GetWindowText (strOldText);
if (strOldText != strText) {
pWnd->SetWindowText (strText);
pWnd->Invalidate();
pWnd->UpdateWindow();
}
}
Revision History
- 7th August, 2002: Added methods
update()
,getElapsedTime (CString&)
andgetRemainingTime (CString&)
- 21st April, 2002: Bug fix:
stop()
was not updating the current time - 16th April, 2002: Initial version