MFC用戶界面多線程實例1

本程序基於 VS2008,參考 MFC demo 做的。


寫該文章的作用給自己做個備份,以後好直接用自己寫好的代碼。隨便發表出來,賺點人氣。


工程中新建一個基於 CWinThread 的類 CGift .

CGift 內部需要一個變量記錄其對象個數,以及何時初始化臨界區,銷燬臨界區。

還有一個臨界區變量。

屏蔽 MFC 界面線程採用的消息循環,採用事件機制運行和結束線程。


頭文件部分代碼如下:


class CGift : public CWinThread
{
	DECLARE_DYNAMIC(CGift)

protected:
//	CGift();           // 動態創建所使用的受保護的構造函數
	virtual ~CGift();
	CGift(CWnd* pWnd, HDC hDC);

public:
	virtual BOOL InitInstance();
	virtual int ExitInstance();
	void Delete();

public:
	void KillThread();
	void UpdateBorder();
	virtual void SingleStep() = 0;
	
public:
	HANDLE m_hEventKill;
	HANDLE m_hEventDead;
	
	CRect  m_rectBorder;
	HDC    m_hDC;
	CDC*   m_pDC;

protected:
	static CRITICAL_SECTION m_csGiftLock;
private:
	static int m_nCounter; //記錄類對象個數
public:
	inline int GetThreadCount(){return m_nCounter;}

protected:
	DECLARE_MESSAGE_MAP()
};

源文件部分代碼如下:


//=========== Class CGift Area =================

CRITICAL_SECTION CGift::m_csGiftLock;
int CGift::m_nCounter = 0;
// CGift

//IMPLEMENT_DYNCREATE(CGift, CWinThread)
IMPLEMENT_DYNAMIC(CGift, CWinThread)

CGift::CGift(CWnd* pWnd, HDC hDC)
{
	m_bAutoDelete = FALSE; // 線程不隨着類對象的消亡而終止
	m_pMainWnd = pWnd;
	m_pMainWnd->GetClientRect(&m_rectBorder);
	m_hDC = hDC;
	m_pDC = new CDC;

	m_nCounter++;

	m_hEventKill = CreateEvent(NULL, TRUE, FALSE, NULL);
	m_hEventDead = CreateEvent(NULL, TRUE, FALSE, NULL);
}

CGift::~CGift()
{
	m_nCounter--;
	delete m_pDC;

	CloseHandle(m_hEventDead);
	CloseHandle(m_hEventKill);
}

BOOL CGift::InitInstance()
{
	// TODO: 在此執行任意逐線程初始化
	m_pDC->Attach(m_hDC);
	if (m_nCounter == 1)
	{
		InitializeCriticalSection(&CGift::m_csGiftLock);
	}	

	while (WaitForSingleObject(m_hEventKill, 0) == WAIT_TIMEOUT)
	{
		SingleStep();
	}

	return FALSE; // 不進入消息循環
	//return TRUE;
}

void CGift::Delete()
{
	CWinThread::Delete();

	SetEvent(m_hEventDead);
}

int CGift::ExitInstance()
{
	// TODO: 在此執行任意逐線程清理
	if (m_nCounter == 1)
	{
		DeleteCriticalSection(&CGift::m_csGiftLock);
	}
	m_pDC->Detach();
	return CWinThread::ExitInstance();
}

void CGift::KillThread()
{
	SetEvent(m_hEventKill);
	
	SetThreadPriority(THREAD_PRIORITY_ABOVE_NORMAL);
	WaitForSingleObject(m_hEventDead, INFINITE);
	WaitForSingleObject(m_hThread, INFINITE);

	delete this;
}

void CGift::UpdateBorder()
{
	EnterCriticalSection(&CGift::m_csGiftLock);
	{
		m_pMainWnd->GetClientRect(&m_rectBorder);
	}
	LeaveCriticalSection(&CGift::m_csGiftLock);
}

BEGIN_MESSAGE_MAP(CGift, CWinThread)
END_MESSAGE_MAP()


// CGift 消息處理程序

//========= end ========================

線程啓動會自動調用 InitInstance() 函數, 線程退出會自動調用 ExitInstance() 函數。在類對象析構前,會調用 Delete() 函數。 MFC 內部實現,無需用戶操心。

在重載這幾個函數,可以自己添加代碼。

函數 SingleStep() 是線程要完成的事。由繼承類做。


關於 IMPLEMENT_DYNCREATE 和 IMPLEMENT_DYNAMIC , 可以視情況而定。


接下來在新建一個繼承 CGift 的 類 CFire , 該類爲用戶 DIY 類,自己設定其功能,調用該類。


頭文件部分代碼:


class CFire : public CGift
{
	DECLARE_DYNAMIC(CFire)

#define RECTANGLE_LENGTH 200  // 矩形長 
#define RECTANGLE_WIDTH  200  // 矩形寬


public:
	CFire(CWnd* pWnd, HDC hDC, CRect rectangle);
	CFire(CWnd* pWnd, HDC hDC, CPoint centrePoint);
	~CFire();

public:
	virtual BOOL InitInstance();
	virtual BOOL ExitInstance();
	virtual void SingleStep();

	CRect  m_rectangle;
	CPoint m_point;
	CBrush m_brush;
	char   m_flag;
};

源文件部分代碼如下:


//========  Class CFire Area ===========

IMPLEMENT_DYNAMIC(CFire, CGift)

CFire::CFire(CWnd* pWnd, HDC hDC, CRect rectangle)
: CGift(pWnd, hDC)
{
	m_rectangle = rectangle;
}

CFire::CFire(CWnd* pWnd, HDC hDC, CPoint centrePoint)
: CGift(pWnd, hDC)
{
	m_rectangle.SetRect(centrePoint.x - RECTANGLE_LENGTH/2, centrePoint.y - RECTANGLE_WIDTH/2,
		                centrePoint.x + RECTANGLE_LENGTH/2, centrePoint.y + RECTANGLE_WIDTH/2);
	m_point.x = centrePoint.x;
	m_point.y = m_rectangle.bottom;
}

CFire::~CFire()
{
	
}

BOOL CFire::InitInstance()
{
	return CGift::InitInstance();
}

BOOL CFire::ExitInstance()
{
	CBrush brush(RGB(0,0,0));
	EnterCriticalSection(&CGift::m_csGiftLock);
	{
		m_pDC->FillRect(m_rectangle,&brush);
//	    m_pDC->FillSolidRect(m_rectangle, m_dc.GetBkColor());
		GdiFlush();
	}
	LeaveCriticalSection(&CGift::m_csGiftLock);

	return CGift::ExitInstance();
}

void CFire::SingleStep()
{
	if (m_point.y-- < m_rectangle.top)
	{
		m_point.y = m_rectangle.bottom;
	}

	EnterCriticalSection(&CGift::m_csGiftLock);
	{
		for (int i = -10; i < 11; i++)
		{
			m_pDC->SetPixelV(m_point.x + i, m_point.y, RGB(121,37,69));
		}

		if ((m_rectangle.bottom - m_point.y) > 10)
		{
			for (int i = -10; i < 11; i++)
			{
				m_pDC->SetPixelV(m_point.x + i, m_point.y+10, RGB(0,0,0));
			}
		}
		GdiFlush();
	}
	LeaveCriticalSection(&CGift::m_csGiftLock);

	Sleep(10);
}

//========  end ====================

關於調用問題。

調用類創建線程如下:

	m_pThread = new CFire(this, m_pDC->GetSafeHdc(), point);

	m_pThread->CreateThread(CREATE_SUSPENDED);
	m_pThread->SetThreadPriority(THREAD_PRIORITY_IDLE);
	m_pThread->ResumeThread();

	m_threadList.AddTail(m_pThread);


每創建一個線程,則在列表中保存下來。


相關變量聲明部分:

	CTypedPtrList<CObList, CGift*>     m_threadList;
	CClientDC* m_pDC;
	CGift*     m_pThread;

關於 m_pDC

int CBirthdayGiftView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
	if (CView::OnCreate(lpCreateStruct) == -1)
		return -1;

	// TODO:  在此添加您專用的創建代碼
	m_pDC = new CClientDC(this);

	return 0;
}

銷燬線程代碼如下:

void CBirthdayGiftView::OnKillthreads()
{
	while (!m_threadList.IsEmpty())
	{
		m_threadList.RemoveHead()->KillThread();
	}
}

void CBirthdayGiftView::OnDestroy()
{
	OnKillthreads();

	CView::OnDestroy();

	// TODO: 在此處添加消息處理程序代碼
}





發佈了34 篇原創文章 · 獲贊 6 · 訪問量 7萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章