Introduction
This application explains how to use a thread in a dialog based MFC application. It demonstrates how threads work independently from each other and how to control thread execution.
Background
Suppose you have to write an application in which two actions are running simultaneously. In such a case, threads is one of the options.
Using the code
Now, we will make two threads which display 1 to 100 count in two edit boxes of a dialog box. Each thread is started by its own button. Each time, a button flag runs or stops thread execution. Each thread has its own thread data structure.
Press the Run button to run a thread and the Stop button to stop a thread.
#include "stdafx.h"
#include "StopClock.h"
#include "StopClockDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
typedef struct tagThreadData{
CStopClockDlg* pObjDlg;
INT* pnEditBoxValue;
UINT nEditId;
}THREADDATA;
THREADDATA* TD1 = new THREADDATA;
THREADDATA* TD2 = new THREADDATA;
BOOL bRunT1 = FALSE;
BOOL bRunT2 = FALSE;
BOOL bFirstTimeT1 = TRUE;
BOOL bFirstTimeT2 = TRUE;
UINT WorkerThreadFunction(LPVOID pParam)
{
THREADDATA* pData = (THREADDATA*) pParam;
INT* pnEditBoxValue = pData->pnEditBoxValue;
UINT nEid = pData->nEditId;
CStopClockDlg* pDlg = pData->pObjDlg;
while(1){
if(*pnEditBoxValue < 100){
(*pnEditBoxValue) ++;
}else{
*pnEditBoxValue = 1;
}
pDlg->SetDlgItemInt(nEid, *pnEditBoxValue);
::Sleep(50);
}
return 0;
}
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
END_MESSAGE_MAP()
CStopClockDlg::CStopClockDlg(CWnd* pParent )
: CDialog(CStopClockDlg::IDD, pParent)
{
m_E1 = 1;
m_E2 = 1;
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CStopClockDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT1, m_E1);
DDX_Text(pDX, IDC_EDIT2, m_E2);
}
BEGIN_MESSAGE_MAP(CStopClockDlg, CDialog)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, OnButton1)
ON_BN_CLICKED(IDC_BUTTON2, OnButton2)
END_MESSAGE_MAP()
BOOL CStopClockDlg::OnInitDialog()
{
CDialog::OnInitDialog();
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
SetIcon(m_hIcon, TRUE); SetIcon(m_hIcon, FALSE);
SetDlgItemText(IDC_BUTTON1, "Run");
SetDlgItemText(IDC_BUTTON2, "Run");
TD1->pObjDlg = this;
TD1->pnEditBoxValue = &m_E1;
TD1->nEditId = IDC_EDIT1;
TD2->pObjDlg = this;
TD2->pnEditBoxValue = &m_E2;
TD2->nEditId = IDC_EDIT2;
return TRUE; }
void CStopClockDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
void CStopClockDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
HCURSOR CStopClockDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
void CStopClockDlg::OnButton1()
{
bRunT1 = !bRunT1;
if(bRunT1){
SetDlgItemText(IDC_BUTTON1, "PAUSE");
}else{
SetDlgItemText(IDC_BUTTON1, "RUN");
}
if(bFirstTimeT1){
theApp.m_pThreads [0]=AfxBeginThread(WorkerThreadFunction,TD1);
bFirstTimeT1 = FALSE;
}
if(bRunT1){
theApp.m_pThreads[0]->ResumeThread();
}else{
theApp.m_pThreads[0]->SuspendThread();
}
}
void CStopClockDlg::OnButton2()
{
bRunT2 = !bRunT2;
if(bRunT2){
SetDlgItemText(IDC_BUTTON2, "PAUSE");
}else{
SetDlgItemText(IDC_BUTTON2, "RUN");
}
if(bFirstTimeT2){
theApp.m_pThreads [1]=AfxBeginThread(WorkerThreadFunction,TD2);
bFirstTimeT2 = FALSE;
}
if(bRunT2 ){
theApp.m_pThreads[1]->ResumeThread();
}else{
theApp.m_pThreads[1]->SuspendThread();
}
}
Please reply to me if you have any difficulties with this code. Thank you...