問題描述:如在攝像頭顯示時,關閉攝像頭,此時Picture控件仍然顯示最后一幀圖像,需要刷新掉,還原Picture控件。或者重復顯示兩張不同大小的圖片時,第二張背景有第一張圖片殘留。
解決方法1:(最笨的方法)
用對話框背景色來填充控件,
CRect rect; GetDlgItem(IDC_ShowImage)->GetClientRect(&rect); GetDlgItem(IDC_ShowImage)->GetDC()->FillSolidRect(&rect2, RGB(255, 255, 255));//可能會把邊界線也刷掉 //CRect rect2(rect.left+1 , rect.top+1 , rect.Width()-1 , rect.Height()-1 ); //可以轉化一下,但治標不治本
解決方法2:
(1)Invalidate(); //使整個窗體無效,全部重繪
(2)GetDlgItem(IDC_ShowImage)->Invalidate(true);//使控件部分無效,進行重繪,但測試發現好像無效,原因不知,有知道的可以留言告知,謝謝!
Invalidate()是使整個窗口客戶區無效, 窗口的客戶區無效意味着需要重繪,會將整個窗口下所有控件都給刷新,一般會造成閃爍。
Invalidate標記一個需要重繪的無效區域,並不意味着調用該函數后就立刻進行重繪。類似於PostMessage(WM_PAINT),需要處理到WM_PAINT消息時才真正重繪。
Invalidate里面有個bool型的參數,用來標識重繪的時候是否用背景色填充,默認為true。
注意:UpdateWindow() 則是要求系統對區域進行立即重繪。向窗體發送WM_PAINT消息,在發送之前判斷GetUpdateRect(hWnd,NULL,TRUE)看有無可繪制的客戶區域,如果沒有,則不發送WM_PAINT。
設想了一下:直接UpdateWindow()是不執行的,因此,
InvalidateRect(rect); //聲明無效區 UpdateWindow(); //進行重繪
確實重繪了,但由於相對坐標系的問題,導致重繪區域不是想要的,方法3會講解原因以及解決方法。
UpdateData()這個函數不是刷新界面用的。
UpdateData()參數為FALSE時,將界面上控件綁定的變量的數據導到控件內,參數為TRUE時,導入方向則相反。
解決方法3:(比較推薦的)
這是因為該種方法得到的 rect是控件客戶區坐標, 而InvalidateRect ,RedrawWindow用的卻是對話框客戶區坐標,所以在使用InvalidateRect、RedrawWindow 之前 必須將其他坐標系下的坐標進行轉換,否則不能按預想的執行。
CWnd* pWnd = GetDlgItem(IDC_ShowImage); pWnd->GetClientRect(&rect);//得到控件客戶端區域坐標 pWnd->ClientToScreen(rect);//將區域坐標由 控件客戶區轉成對話框區 //pWnd->GetWindowRect(&rect); //直接得到控件的對話框區坐標 this->ScreenToClient(rect); //將區域坐標由 對話框區轉成對話框客戶區坐標 InvalidateRect(rect); //RedrawWindow(rect);
這里面有幾個需要注意的點:
1.可以通過GetWindowRect直接獲取控件相對於對話框區坐標。
2. 注意對話框區和對話框客戶區的區別。(參考鏈接2)
3.在這里,InvalidateRect(rect);和RedrawWindow(rect)效果一樣,這是由於消息隊列消息很少,所以執行很快,但需要注意:
InvalidateRect()不能實現立即更新 ;
InvalidateRect()與 UpdateWindow()結合后可以實現立即更新;
兩者結合的效果相當於RedrawWindow(rect)。
參考鏈接:
(1) InvalidateRect()、UpdateWindow()、RedrawWindow()區別
http://blog.csdn.net/shuilan0066/article/details/6826000
(2) GetWindowRect和GetClientRect的區別詳解
http://www.cnblogs.com/wb-DarkHorse/archive/2013/07/08/3178201.html
(3) 使用InvalidateRect(rect) 防止圖片移動時發生閃爍
http://blog.csdn.net/shuilan0066/article/details/6676229