MFC界面更新實現方法 MFC重繪函數 線程調用UpdateData函數出錯 MFC添加自定義消息 SendMessage和PostMessage區別

1.更新窗口html

即採用UpdateWindow()函數當即發送WM_PAINT消息更新整個窗口。函數

void CEditTestDlg::OnBnClickedBtnSysUpdate()
{
    CString csTmp;
    int i = 0;
    while (i < 100)
    {
        Sleep(20);
        i += 1;
        csTmp.Format(_T("%d"),i);
        m_value = csTmp;//沒法更新只顯示結果
        //m_editNum.SetWindowText(csTmp);//沒法更新也不顯示結果
        UpdateData(FALSE);
        UpdateWindow();//能更新但再次操做會卡死
        //Invalidate(FALSE);//沒法更新只顯示結果
        //RedrawWindow(NULL,NULL,RDW_INVALIDATE | RDW_UPDATENOW | RDW_ERASE);//RDW_INVALIDATE和Invalidate()效果同樣,RDW_ERASE致使閃爍
    }
}

可是這會致使界面假死,更新過程當中沒法對窗口進行任何操做。控件的Control變量有時候沒法更新Invalidate()通常都在多文檔對話框裏使用,RedrawWindow()是前兩個都會去調用的函數,方式更多。詳情見:MFC重繪函數post

2. 定時器實現測試

在須要更新的位置調用SetTimer()啓動定時器,在定時器響應函數OnTimer()裏面來處理更新,能夠同時啓用多個定時器更新多個位置。this

啓動定時器:url

void CEditTestDlg::OnBnClickedBtnTimerUpdate()
{
    this->SetTimer(1,1,NULL);
    this->SetTimer(2,1,NULL);
}

定時器內部處理:spa

void CEditTestDlg::OnTimer(UINT_PTR nIDEvent)
{
    switch (nIDEvent)
    {
    case 1:
        if (tmp >= 100)
        {
            this->KillTimer(1);
            MessageBox(_T("定時器1中止!"), NULL, NULL);
            return;
        }
        Sleep(20);
        tmp += 1;
        m_value.Format(_T("%d"),tmp);
        UpdateData(FALSE);
        break;
    case 2:
        if (tmp1 >= 200)
        {
            this->KillTimer(2);
            MessageBox(_T("定時器2中止!"), NULL, NULL);
            return;
        }
        Sleep(20);
        tmp1 += 1;
        m_value2.Format(_T("%d"),tmp1);
        UpdateData(FALSE);
    default:
        break;
    }
    CDialog::OnTimer(nIDEvent);
}

經過定時器界面不會假死,實現也簡單明瞭。線程

3. 線程更新翻譯

建立一個新的線程來更新界面,建立線程:code

void CEditTestDlg::OnBnClickedBtnThreadUpdate()
{
    CWinThread* pThread;
    pThread = AfxBeginThread(UpdateThread,this);
}

線程內部實現:

static UINT UpdateThread(LPVOID lpParam)
{
    CEditTestDlg *dlg = (CEditTestDlg*) lpParam;
    int i = 0;
    while (i < 200)
    {
        Sleep(20);
        i += 1;
        dlg->m_value2.Format(_T("%d"), i);
        //dlg->UpdateData(FALSE);//release下可行
        dlg->m_editCtl.SetWindowText(dlg->m_value2);//使用control變量
        //dlg->GetDlgItem(IDC_EDIT2)->SetWindowText(dlg->m_value2);
    }
    return 0;
}

在這裏,最好不要用UpdateData(FALSE)來顯示到界面,在Debug下回奔潰,而Release模式下沒有任何問題,具體見:線程調用UpdateData函數出錯

4. 線程中發送自定義消息更新

在線程中給窗口發送自定義的更新界面的消息,讓消息加入系統消息隊列達到更新界面的目的。自定義消息可參照:MFC添加自定義消息

void CEditTestDlg::OnBnClickedBtnMsgUpdate()
{
    CWinThread* pThread;
    pThread = AfxBeginThread(SendMsgThread,this);
}
static UINT SendMsgThread(LPVOID lpParam)
{
    CEditTestDlg *dlg = (CEditTestDlg*) lpParam;
    int i = 0;
    while (i < 100)
    {
        Sleep(20);
        i += 1;
        dlg->m_value2.Format(_T("%d"), i);
        //PostMessage(dlg->m_hWnd,WM_UPDATEDATA,FALSE,NULL);
        //SendMessage(dlg->m_hWnd,WM_UPDATEDATA,FALSE,NULL);
        SendMessageTimeout(dlg->m_hWnd, WM_UPDATEDATA, FALSE,NULL, SMTO_BLOCK, 1000, NULL);
    }
    return 0;
}

發送消息的時候PostMessage(),SendMessage()SendMessageTimeout()均可以實現,具體區別見:SendMessage和PostMessage區別

5. 設備繪製更新

直接在界面中不停的繪製變化的部分,這種方法也會形成假死。

void CEditTestDlg::OnBnClickedBtnDrawUpdate()
{
    CString csTmp;
    int i = 0;
    CDC* pDC = this->GetDC();
    while (i < 100)
    {
        Sleep(20);
        i += 1;
        csTmp.Format(_T("%d"),i);
        pDC->TextOut(20, 100, csTmp);
    }
    ReleaseDC(pDC);
}

6. STATIC控件更新

給STATIC控件賦值更新,一樣會形成假死現象。(值得一提的是之前在VC6.0中能夠對EIDT控件使用一樣的方法更新而如今去測試卻不行,但願有經驗的人給予指導。

void CEditTestDlg::OnBnClickedBtnStaticUpdate()
{
    CString csTmp;
    int i = 0;
    while (i < 100)
    {
        Sleep(20);
        i += 1;
        csTmp.Format(_T("%d"),i);
        m_csStaticNum = csTmp;//能更新但再次操做會卡死
        //m_staticCtlNum.SetWindowText(csTmp);//不更新也不顯示結果
        UpdateData(FALSE);
    }
}

7. 發送系統消息更新

直接給系統消息循環發送WM_PAINT消息來更新界面,可是一樣會出現假死狀況,因此能夠建立一個函數DoEvent()實現:在有系統消息,如拖動點擊等消息時,暫停處理咱們發送的消息而優先去處理系統消息。

void CEditTestDlg::OnBnClickedBtnMsg()
{
    CString csTmp;
    int i = 0;
    while (i < 100)
    {
        Sleep(20);
        i += 1;
        csTmp.Format(_T("%d"),i);
        m_value = csTmp;//能更新但再次操做會卡死
        //m_editNum.SetWindowText(csTmp);//沒法更新也不顯示結果
        UpdateData(FALSE);
        GetDlgItem(IDC_EDIT1)->SendMessage(WM_PAINT);//能更新但再次操做會卡死
        DoEvents();//轉出處理系統消息
    }
}
//有系統消息時暫停處理系統消息
void DoEvents()
{
    MSG msg; //定義一個MSG類型的變量
    while(PeekMessage(&msg,NULL,0,0,PM_REMOVE)) //獲取消息並把該消息從消息隊列中移除(防止重複響應)。
    {
        TranslateMessage(&msg);//翻譯消息 在合適的機會產生char消息
        DispatchMessage(&msg); //將消息移交給過程函數
    }
}

可是出現的問題是,咱們在拖動對話框的時候,界面中止了更新。

 

因此比較而言,線程發送消息和定時器效果相對較好,界面不會假死,在進行拖動等操做的時候也不會出現中止等待的現象。

相關文章
相關標籤/搜索