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); //將消息移交給過程函數 } }
可是出現的問題是,咱們在拖動對話框的時候,界面中止了更新。
因此比較而言,線程發送消息和定時器效果相對較好,界面不會假死,在進行拖動等操做的時候也不會出現中止等待的現象。