使用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线程的基本操作就完成了。

 

posted @ 2021-06-03 15:05  大笨瓜  阅读(741)  评论(0)    收藏  举报