Introduction
It seems to be a frequent problem that a developer wants to offer the ability
to pause and restart a loop. Sometimes, this can be handled by placing processing
in a thread. Other times, it would be preferable to avoid that complexity. This
article shows how you can do this with a minimal use of system resources when
paused.
What You Need
This technique uses three controls (StartButton,StopButton, and PauseCheckbox).
These are the event handlers for the start button and the stop button. There
is no handler for the checkbox.
void __fastcall TMainForm::StartButtonClick(TObject *Sender)
{
Screen->Cursor = crHourGlass;
StartButton->Enabled = false;
PauseCheckBox->Enabled = true;
PauseCheckBox->Checked = false;
StopButton->Enabled = true;
while (Whatever() && !StopPending)
{
Application->ProcessMessages();
// Note - a WM_CLOSE can kill this loop right here
while (PauseCheckBox->Checked
&& !StopPending)
{
WaitMessage();
// Waits for any message to appear in the queue, including a click on the check
box
Application->ProcessMessages();
// Note - a WM_CLOSE can kill this loop right here
};
};
StopPending = false;
PauseCheckBox->Enabled = false;
PauseCheckBox->Checked = false;
StopButton->Enabled = false;
Screen->Cursor = crDefault;
StartButton->Enabled = true;
}
//---------------------------------------------------------------------------
void __fastcall TMainForm::StopButtonClick(TObject *Sender)
{
StopPending = true;
}
//---------------------------------------------------------------------------
How It Works
These function use the Windows API function WaitMessage to allow
the function to wait for the click on the pause check box or the stop button.
Since WaitMessage does not process the message, it then lets the application
do so.
One approach frequently cited for this problem is to loop on Application->ProcessMessages.
Unfortunately, this does not conserve system resources during the pause. If
there are no messages in the queue, it simply returns control to the main thread.
What Needs To Be Done
This logic doesn't completely handle the issue of the user trying to close
the app. You could simply have the form OnCloseQuery return StartButton->Enabled
(if it is enabled we aren't in the loop), which would prevent closing without
having first hit Stop.
|