使用AfxBeginThread创建界面线程
首先创建一个界面类,在界面类里面添加一个进度条做演示
1 #pragma once 2 #include <afxwin.h> 3 class CMyWnd : 4 public CFrameWnd 5 { 6 7 public: 8 DECLARE_MESSAGE_MAP() 9 afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); 10 private: 11 CProgressCtrl m_pos; 12 public: 13 afx_msg void OnTimer(UINT_PTR nIDEvent); 14 afx_msg void OnDestroy(); 15 };
实现方法:
1 #include "pch.h" 2 #include "CMyWnd.h" 3 BEGIN_MESSAGE_MAP(CMyWnd, CFrameWnd) 4 ON_WM_CREATE() 5 ON_WM_TIMER() 6 ON_WM_DESTROY() 7 END_MESSAGE_MAP() 8 9 10 int CMyWnd::OnCreate(LPCREATESTRUCT lpCreateStruct) 11 { 12 if (CFrameWnd::OnCreate(lpCreateStruct) == -1) 13 return -1; 14 15 // TODO: 在此添加您专用的创建代码 16 17 m_pos.Create(WS_CHILD | WS_VISIBLE, CRect(10, 10, 300, 50), this, 10001); 18 m_pos.SetRange(0, 100); 19 m_pos.SetStep(1); 20 SetTimer(1, 100, 0); 21 return 0; 22 } 23 24 25 void CMyWnd::OnTimer(UINT_PTR nIDEvent) 26 { 27 // TODO: 在此添加消息处理程序代码和/或调用默认值 28 m_pos.StepIt(); 29 30 CFrameWnd::OnTimer(nIDEvent); 31 } 32 33 34 void CMyWnd::OnDestroy() 35 { 36 CFrameWnd::OnDestroy(); 37 38 // TODO: 在此处添加消息处理程序代码 39 KillTimer(1); 40 }
在窗口创建的时候,创建进度条窗口,并设置进度条信息
启动一个定时器,定时更新进度条的进度。添加清理虚函数,结束定时器
创建基于CWinThread的类
1 #pragma once 2 #include <afxwin.h> 3 class MyThread : 4 public CWinThread 5 { 6 DECLARE_DYNCREATE(MyThread) 7 public: 8 virtual BOOL InitInstance(); 9 protected: 10 DECLARE_MESSAGE_MAP(); 11 };
注意:此类必须创建消息循环,否则将会导致AfxBegenThread函数内存不足。并且该类必须重写初始化函数。
实现方法:
1 #include "pch.h" 2 #include "MyThread.h" 3 #include"CMyWnd.h" 4 5 IMPLEMENT_DYNCREATE(MyThread, CWinThread); 6 7 BOOL MyThread::InitInstance() 8 { 9 // 当前的函数将会运行在线程中。 10 CWinThread::InitInstance(); 11 // TODO: 在此添加专用代码和/或调用基类 12 CMyWnd* Dlg = new CMyWnd(); 13 Dlg->Create(NULL, "线程窗口"); 14 Dlg->ShowWindow(SW_SHOW); 15 Dlg->UpdateWindow(); 16 17 return TRUE; //返回TRUE表示线程会进入消息循环,不会立即退出,返回FALSE则线程运行后立即退出。 18 } 19 20 BEGIN_MESSAGE_MAP(MyThread, CWinThread) 21 END_MESSAGE_MAP()
以上步骤做完后,就可以使用AfxBeginThread来创建界面线程了。
1 void CMFCApplicationDlg::OnBnClickedTest() 2 { 3 // TODO: 在此添加控件通知处理程序代码 4 AfxBeginThread(RUNTIME_CLASS(MyThread)); 5 }
AfxBeginThread有两个版本,一个是界面线程版本,一个是工作线程版本。都是属于MFC的全局API。
创建完线程后,线程运行了一个窗口,这个窗口在线程的消息循环中运行,当窗口关闭后,线程的消息循环并不会结束,所以这里要向线程发送退出消息。
2、下面是一个没有界面的线程消息循环:
class CMyThread : public CWinThread { DECLARE_DYNCREATE(CMyThread) protected: CMyThread(); // 动态创建所使用的受保护的构造函数 virtual ~CMyThread(); public: virtual BOOL InitInstance(); virtual int ExitInstance(); // 线程的消息处理函数,当前线程支持接收消息,处理函数将在线程中执行。 afx_msg void Message(WPARAM, LPARAM); protected: DECLARE_MESSAGE_MAP() };
编写对应的消息映射:
IMPLEMENT_DYNCREATE(CMyThread, CWinThread)
BEGIN_MESSAGE_MAP(CMyThread, CWinThread) ON_THREAD_MESSAGE(5688,&CMyThread::Message) END_MESSAGE_MAP()
当向线程发送id为5688的消息时,线程将会执行Message事件处理。
注意:
BOOL CMyThread::InitInstance() { // TODO: 在此执行任意逐线程初始化 return TRUE; }
函数要返回TRUE,这样线程才能进入消息循环,不会直接退出。
因为要向线程发送消息,所以要保存线程函数的返回值,来操作。
m_Thread = AfxBeginThread(RUNTIME_CLASS(CMyThread));
m_Thread是一个CWinThread*的成员变量,它保存了线程的信息。
向线程发消息:
PostThreadMessage(m_Thread->m_nThreadID, 5688, static_cast<WPARAM>(0), static_cast<LPARAM>(0));
如果要销毁当前的线程,需要让线程退出消息循环,否则就是内存泄漏:
PostThreadMessage(m_Thread->m_nThreadID, WM_QUIT, 0, 0);
线程在退出消息循环后,会进入清理函数,可以在清理函数中清理线程中创建的堆堆内存或者其他资源。
int CMyThread::ExitInstance() { // TODO: 在此执行任意逐线程清理 CDebug() << "线程已退出。。。" << "\n"; return CWinThread::ExitInstance(); }
线程彻底退出后,线程对象将被自动销毁,自动销毁是因为
AfxBeginThread函数的特性,如果你没有操作他返回的对象的m_Thread->m_bAutoDelete=FALSE;那么默认是自动销毁的。
至此MFC线程的基本操作就完成了。

浙公网安备 33010602011771号