Updating a Gauge and Detecting a User Interrupt (C++ 5.0 and later)
Take the following steps to update a gauge during processing and detect a user interrupt:
1. |
Start with the project that you created in Loading and Displaying an Image |
|
2. |
Go to the Project WorkSpace and click the ResourceView tab. |
|
3. |
Double-click Dialog and double-click IDD_TUTOR_DIALOG to bring up the application's dialog box. |
|
4. |
Add a new button under the Cancel button. To do this, select the button control on the Controls toolbar. Then, click and drag to position the button on the dialog box. |
|
5. |
Add another button under the previously added button. |
|
6. |
Double-click the first button and change IDC_BUTTON1 to IDC_MEDIAN. Also, set the caption to Do &Median. |
|
7. |
Double-click the second button and change IDC_BUTTON2 to IDC_QUIT. Also, set the caption to &Quit. |
|
8. |
To build a gauge, select the Progress control on the Controls toolbar. (If you do not have a Progress control, you can use any control that has a rectangular shape and a border.) Put the gauge at the top of the dialog box to keep it away from the image. |
|
9. |
Double-click on the gauge and change the ID from IDC_PROGRESS1 to IDC_GAUGE. |
|
10. |
Close all the windows until you reach the project window, answering yes when asked whether to save the changes. |
|
11. |
Press Ctrl-W to go to the MFC Class Wizard; then do the following: |
|
|
a. |
In the Class name combo box, select CTutorDlg. |
|
b. |
In the Object IDs list box, select IDC_MEDIAN. |
|
c. |
In the Messages list box, select BN_CLICKED. |
|
d. |
Click the Add function button. Choose OK for the default function name (OnMedian). |
|
e. |
Click the Edit Code button to start entering the code. |
12. |
Enter new code as follows: |
void CTutorDlg::OnMedian()
{
// TODO: Add your control notification handler code here
// Enable the ProgressStatus event
m_pRasterProc->PutEnableProgressEvent( TRUE );
// Initialize the indicators
fEscape = FALSE; // The user does not want to quit
fInProc = TRUE; // Processing is taking place
// Perform a relatively slow median filter
m_pRasterProc->Median(m_LEADRasterView1.GetRaster(), 4);
// Clean up
fInProc = FALSE; // Processing is no longer taking place
m_LEADRasterView1.ForceRepaint();
// reset the gauge
GetDlgItem(IDC_GAUGE)->InvalidateRect(NULL, TRUE);
}
13. |
Press Ctrl-W to go to the MFC Class Wizard; then do the following: |
|
|
a. |
In the Class name combo box, select CTutorDlg. |
|
b. |
In the Object IDs list box, select IDC_QUIT. |
|
c. |
In the Messages list box, select BN_CLICKED. |
|
d. |
Click the Add function button. Choose OK for the default function name (OnQuit). |
|
e. |
Click the Edit Code button to start entering the code. |
14. |
Enter new code as follows: |
void CTutorDlg::OnQuit()
{
// TODO: Add your control notification handler code here
fEscape = TRUE; // The user wants to quit
// Set the gauge back to the beginning
GetDlgItem(IDC_GAUGE)->InvalidateRect(NULL, TRUE);
}
15. |
Edit the TUTORDLG.H file and change the definition of CTutorDlg : CDialog by inserting the following lines after DECLARE_MESSAGE_MAP: |
public:
BOOL fInProc;
BOOL fEscape;
ILEADRasterProcess *m_pRasterProc;
CRasterProcSink *m_pRasterProcSink;
IConnectionPoint *m_pCP;
DWORD m_dwCookie;
16. |
Edit the TUTORDLG.CPP file and add the following code to the end of the OnInitDialog function: |
//Instantiate the sink class and hold a pointer to it.
m_pRasterProcSink = new CRasterProcSink;
m_pRasterProcSink->m_pDlg = this;
//Create the RasterProcess object
CoCreateInstance(CLSID_LEADRasterProcess, NULL, CLSCTX_ALL,
IID_ILEADRasterProcess, (void**)&m_pRasterProc);
//Establish a connection between source and sink.
LPUNKNOWN pUnkSink = m_pRasterProcSink->GetIDispatch(FALSE);
AfxConnectionAdvise(m_pRasterProc, DIID__LEADRasterProcessEvents, pUnkSink, FALSE, &m_dwCookie);
fInProc = FALSE;
17. |
Press Ctrl-W to go to the MFC Class Wizard; then do the following: |
|
|
a. |
Click the Add Class button. |
|
b. |
Click New.... |
|
c. |
Type CRasterProcSink for the name of the class |
|
d. |
Select CCmdTarget for the base class of the new class. |
|
e. |
Under Automation, click the Automation radio button. |
|
f. |
Click OK to create the class. |
|
g. |
In the RasterProcSink.h file, move the destructor so that it is public: |
// Implementation
virtual ~CRasterProcSink();
protected:
|
h. |
In the RasterProcSink.h file, add the following to the top of the file: |
|
|
class CTutorDlg; |
|
i. |
In the RasterProcSink.h file, add the following to the CRasterProcSink class in the //Attributes public section: |
// Attributes
public:
CTutorDlg *m_pDlg;
|
j. |
In the RasterProcSink.cpp file, add the following to the top of the file (after the #include "RasterProcSink.h") |
#include "tutorDlg.h"
18. |
Add #include statements so you can access the new class: |
|
|
a. |
In the Project Workspace, click the FileView tab. |
|
b. |
Double-click the tutor files folder to open it. |
|
c. |
Double-click the Header Files folder to open it. |
|
d. |
Double-click the StdAfx.h file to edit it. |
|
e. |
Add the following lines to the end of the file: |
#include <AFXCTL.H>
#include "RasterProcSink.h"
19. |
Edit the header for the Sink class: |
|
|
a. |
In the Project Workspace, click the FileView tab. |
|
b. |
Double-click the tutor files folder to open it. |
|
c. |
Double-click the Header Files folder to open it. |
|
d. |
Double-click the RasterProcSink.h file to edit it. |
|
e. |
Add the following just before //}}AFX_MSG: |
afx_msg void OnProgressStatus(short iPercent);
20. |
Edit the source for the Sink class: |
|
|
a. |
In the Project Workspace, click the FileView tab. |
|
b. |
Double-click the tutor files folder to open it. |
|
c. |
Double-click the Source Files folder. |
|
d. |
Double-click the RasterProcSink.cpp file to edit it. |
|
e. |
Add the following to the DISPATCH_MAP: |
DISP_FUNCTION_ID(CRasterProcSink,"ProgressStatus",1,OnProgressStatus,VT_EMPTY,VTS_I2)
|
f. |
Inside the BEGIN_INTERFACE_MAP section, change the INTERFACE_PART to the following: |
INTERFACE_PART(CRasterProcSink, DIID__LEADRasterProcessEvents, Dispatch)
|
g. |
Add the following to the end of the file: |
void CRasterProcSink::OnProgressStatus(short iPercent)
{
MSG msg;
// are there any messages in the queue (like a button being pressed) ?
while( PeekMessage(&msg,NULL, 0, 0, PM_REMOVE) )
{
TranslateMessage( &msg ); /* Translates virtual key codes. */
DispatchMessage( &msg ); /* Dispatches message to window. */
}
if( !m_pDlg->fEscape ) // Look for the Click on the Quit button
{
CWnd *pwndGauge = m_pDlg->GetDlgItem( IDC_GAUGE );
RECT rcGauge;
pwndGauge->GetClientRect( &rcGauge );
// Update the gauge
short LineLength = (rcGauge.right-rcGauge.left) * iPercent / 100;
CDC *pdc = pwndGauge->GetDC();
CPen hpen( PS_SOLID, rcGauge.bottom - rcGauge.top, RGB(0,0,0) ); // black pen
CPen *pOldPen = pdc->SelectObject(&hpen);
pdc->MoveTo( rcGauge.left, (rcGauge.top + rcGauge.bottom) / 2 );
pdc->LineTo( rcGauge.left + LineLength, (rcGauge.top + rcGauge.bottom) / 2 );
pdc->SelectObject(pOldPen);
}
else
m_pDlg->m_pRasterProc->PutEnableProgressEvent(FALSE); // Cancel the task
}
21. |
Press Ctrl-W to go to the MFC Class Wizard; then do the following: |
|
|
a. |
In the Class name combo box, select CTutorDlg. |
|
b. |
In the Object IDs list box, select CTutorDlg. |
|
c. |
In the Messages list box, select WM_DESTROY. |
|
d. |
Click the Add function button. Choose OK for the default function name (OnDestroy). |
|
e. |
Click the Edit Code button to start entering the code. |
22. |
Enter new code as follows: |
void CTutorDlg::OnDestroy()
{
//Terminate a connection between source and sink.
LPUNKNOWN pUnkSink = m_pRasterProcSink->GetIDispatch(FALSE);
AfxConnectionUnadvise(m_pRasterProc, DIID__LEADRasterProcessEvents,
pUnkSink, FALSE, m_dwCookie);
delete m_pRasterProcSink;
m_pRasterProc->Release();
CDialog::OnDestroy();
}
23. |
Continue with the remaining steps to prevent the user from quitting while a process is still going. This requires additional checks in the handling of the OK and Cancel buttons. |
|
24. |
Press Ctrl-W to go to the MFC Class Wizard; then do the following: |
|
|
a. |
In the Class name combo box, select CTutorDlg. |
|
b. |
In the Object IDs list box, select IDCANCEL. |
|
c. |
In the Messages list box, select BN_CLICKED. |
|
d. |
Click the Add function button. Choose OK for the default function name (OnCancel). |
|
e. |
Click the Edit Code button to start entering the code. |
25. |
Enter new code as follows: |
void CTutorDlg::OnCancel()
{
// TODO: Add extra cleanup here
if( !fInProc )
CDialog::OnCancel();
}
26. |
Press Ctrl-W to go to the MFC Class Wizard; then do the following: |
|
|
a. |
In the Class name combo box, select CTutorDlg. |
|
b. |
In the Object IDs list box, select IDOK. |
|
c. |
In the Messages list box, select BN_CLICKED. |
|
d. |
Click the Add function button. Choose OK for the default function name (OnOK). |
|
e. |
Click the Edit Code button to start entering the code. |
27. |
Enter new code as follows: |
void CTutorDlg::OnOK()
{
// TODO: Add extra validation here
if( !fInProc )
CDialog::OnOK();
}
28. |
Change the MFC settings for this project: |
|
|
a. |
On the main menu, select Project | Settings. |
|
b. |
Select the General tab. |
|
c. |
Under Microsoft Foundation Classes, select Use MFC in a Shared DLL. |
|
d. |
Select OK. |
29. |
Rebuild the application and run the program. |