本程序基於 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: 在此處添加消息處理程序代碼
}