[轉]MFC子線程中更新控件內容的兩種辦法


一、概述

每個系統中都有線程(至少都有一個主線程),而線程最重要的作用就是並行處理,提高軟件的並發率。針對界面來說,還能提高界面的響應能力。一般的,為了應用的穩定性,在數據處理等耗時操作會單獨在一個線程中運行,而所有與主UI線程有關的控件數據刷新應該到主UI線程中處理。也就是數據處理線程發消息,讓界面UI去更新控件。在MFC中線程分為界面線程和工作者線程,界面實際就是一個線程畫出來的東西,這個線程維護一個“消息隊列”,“消息隊列”也是界面線程和工作者線程的最大區別,這個詞應該進到你的腦子里,根深蒂固的!MFC中有兩類線程,分別稱之為工作者線程和用戶界面線程。二者的主要區別在於工作者線程沒有消息循環,而用戶界面線程有自己的消息隊列和消息循環。

 

在MFC中,一般用全局函數AfxBeginThread()來創建並初始化一個線程(工作者線程,還有一個重載形式是用於創建用戶界面線程)的運行。函數原型:

CWinThread* AfxBeginThread(  
   AFX_THREADPROC pfnThreadProc,  
   LPVOID pParam,  
   int nPriority = THREAD_PRIORITY_NORMAL,  
   UINT nStackSize = 0,  
   DWORD dwCreateFlags = 0,  
   LPSECURITY_ATTRIBUTES lpSecurityAttrs = NULL   
);  

返回值: 成功時返回一個指向新線程的線程對象的指針,否則NULL。

pfnThreadProc:線程的入口函數,聲明一定要如下: UINT MyThreadFunction(LPVOID pParam),不能設置為NULL。如果是類成員函數,一定要是靜態成員函數。

pParam:傳遞入線程的參數,注意它的類型為:LPVOID,所以我們可以傳遞一個結構體或者類對象到線程。一般傳遞this指針,以方便調用類的非靜態成員,因為線程函數是靜態函數。

nPriority:線程的優先級,一般設置為0,讓它和主線程具有共同的優先級。

nStackSize:指定新創建的線程的棧的大小。如果為 0,新創建的線程具有和主線程一樣的大小的棧。

dwCreateFlags:指定創建線程以后,線程有怎么樣的標志。可以指定兩個值:CREATE_SUSPENDED:線程創建以后,會處於掛起狀態,直到調用:ResumeThread。0 : 創建線程后就開始運行。

lpSecurityAttrs:指向一個 SECURITY_ATTRIBUTES 的結構體,用它來標志新創建線程的安全性。如果為 NULL,那么新創建的線程就具有和主線程一樣的安全性。

常見用法:

AfxBeginThread(MyThreadFunction, this); 

傳遞線程參數為this,即類本身,是為了能在線程函數中獲得類中非靜態成員變量,因為線程函數是靜態函數。

 

MFC子線程中更新控件內容有兩種方法,一種是在子線程中通過全局函數更新控件內容,一種是在子線程中通過發送自定義消息來更新控件內容。

 

二、通過全局函數更新控件內容

 

1.在對話框類CThreadDemoDlg中添加成員變量——線程對象的指針和線程函數

CWinThread *m_pThread;  
static UINT ThreadFunction(LPVOID pParam);  

2.實現線程函數,使用全局函數::SetWindowText、::GetDlgItem更新控件內容

UINT CThreadDemoDlg::ThreadFunction(LPVOID pParam)  
{  
    CThreadDemoDlg *pDlg = (CThreadDemoDlg *)pParam;  
  
    while (TRUE) {  
        ::SetWindowText(::GetDlgItem(pDlg->m_hWnd, IDC_STATIC), L"Hello World");  
        Sleep(1000);  
        ::SetWindowText(::GetDlgItem(pDlg->m_hWnd, IDC_STATIC), L"Hello Android");  
        Sleep(1000);  
    }  
    return 0;  
}  

3.在成員函數OnInitDialog創建線程並啟動

m_pThread = AfxBeginThread((AFX_THREADPROC)ThreadFunction, this);   

三、通過發送自定義消息更新控件內容

1.在頭文件中定義消息ID

#define WM_UPDATE_STATIC (WM_USER + 100)  

2.在對話框類CThreadDemoDlg中添加成員——線程對象的指針和線程函數

CWinThread *m_pThread;  
static UINT ThreadFunction(LPVOID pParam);  

3.聲明自定義的消息函數

afx_msg LRESULT OnUpdateStatic(WPARAM wParam, LPARAM lParam);  

4.在CPP文件中添加消息映射

BEGIN_MESSAGE_MAP(CThreadDemoDlg, CDialog)  
    //......  
    ON_MESSAGE(WM_UPDATE_STATIC, &CThreadDemoDlg::OnUpdateStatic)  
    //......  
END_MESSAGE_MAP()  

5.實現自定義消息響應函數

LRESULT CThreadDemoDlg::OnUpdateStatic(WPARAM wParam, LPARAM lParam)  
{  
    if (wParam == 0) {  
        GetDlgItem(IDC_STATIC)->SetWindowText(L"Hello Linux");  
    } else {  
        GetDlgItem(IDC_STATIC)->SetWindowText(L"Hello Windows");  
    }  
      
    return 0;  
}  

6.實現線程函數,並通過PostMessage發送自定義消息

UINT CThreadDemoDlg::ThreadFunction(LPVOID pParam)  
{  
    CThreadDemoDlg *pDlg = (CThreadDemoDlg *)pParam;  
  
    while (TRUE) {  
        ::PostMessage(pDlg->m_hWnd, WM_UPDATE_STATIC, 0, 0);  
        Sleep(1000);  
        ::PostMessage(pDlg->m_hWnd, WM_UPDATE_STATIC, 1, 0);  
        Sleep(1000);  
    }  
  
    return 0;  
}  

7.在成員函數OnInitDialog創建線程並啟動

m_pThread = AfxBeginThread((AFX_THREADPROC)ThreadFunction, this);   

 

  通過發送自定義消息更新控件內容總體思路:在主界面所在的主線程中創建線程--->將線程的起始函數綁定到類的靜態成員方法--->在靜態成員方法中調用PostMessage()或SendMessage()發送自定義消息--->在自定義消息的消息響應函數中更新主界面上控件的狀態顯示。

原文鏈接:MFC子線程中更新控件內容的兩種辦法

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM