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;
When you want to start timing, call the object's start()
method.
m_taskTimer.start();
Every now and then, inform the object of your task's progress by calling its updateProgress()
method.
nProgress = ...;
m_taskTimer.updateProgress (nProgress);
To determine the task's elapsed and estimated remaining times, just call the appropriate methods.
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.
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.
m_taskTimer.pause();
TaskTimer API
The TaskTimer
API contains functions to control timing, update progress, and retrieve timing and task state information.
void start();
void pause();
void resume();
void stop();
void update();
void updateProgress
(long nProgress);
void updateProgress
(long nProgress,
long& nRemainingTime);
long getProgress();
long getElapsedTime();
void getElapsedTime
(long& nHours,
long& nMinutes,
long& nSeconds);
void getElapsedTime
(CString& strElapsed);
long getRemainingTime();
void getRemainingTime
(long& nHours,
long& nMinutes,
long& nSeconds);
void getRemainingTime
(CString& strRemaining);
bool isRunning();
bool isPaused();
bool isStopped();
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()
{
m_taskTimer.start();
for (long nTaskIterator=1; (nTaskIterator <= 10); nTaskIterator++) {
doSomething();
m_taskTimer.updateProgress (nTaskIterator * 10);
MSG msg;
while (::PeekMessage (&msg, NULL, 0, 0, PM_NOREMOVE))
AfxGetThread()->PumpMessage();
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&)
and getRemainingTime (CString&)
- 21st April, 2002: Bug fix:
stop()
was not updating the current time - 16th April, 2002: Initial version