這個和視窗繪製的原理有關,需要從頭說起。1、最基本的原理是:繪製是在主執行緒中完成的。主執行緒是什麼,可以理解為就是main()函式。你寫qt程式肯定知道一個基本用法,main()函式最後需要呼叫QApplication的exec()函式,這個exec()裡面是個死迴圈,每次迴圈呼叫一次QApplication的processEvents(),這個函式負責處理視窗事件、使用者訊息,然後繪製視窗。就是說所有這些事都是在主執行緒中依次完成的,並不是同時進行,所以如果你在主執行緒中處理資料(比如響應按鈕事件),你這個事件處理函式不返回,就不會往下走到繪製這一步。2、update和repaint。可能你已經知道,視窗系統為了提高效能,會盡量減少繪製次數和範圍,所以預設情況下,只有視窗內容顯示出來的時候才進行一次繪製,包括視窗被遮擋的部分重新顯現。update和repaint就是主動通知系統繪製視窗內容。區別在於,update只是在內部資料中做一個標記,要等到主執行緒進行到下一次繪製時才進行繪製,所以多次呼叫update是沒有意義的,只是重複設定繪製標記,並不會馬上進行繪製,而且同樣要等到你的程式碼走完之後走到繪製時才能看到結果。repaint雖然可以立即呼叫到paintEvent,但是光有這個paintEvent還不夠,不跑完整個processEvents,缺少了介面響應,你的視窗就是個死的,看上去仍然不是實時顯示。解決方法①(臨時): 在每次update之後都呼叫一次qApp->processEvents()。這種方法的問題在於,processEvents裡面除了繪製還有事件處理等很多內容,提前呼叫會打亂計劃好的處理順序,這在事件處理複雜的程式中容易導致bug,要小心使用。而且不能控制動畫的速度,因為你不能在主執行緒裡面sleep,那樣會卡死整個介面。解決方法②(推薦):拆分for迴圈,放到timer處理函數里面,timer設定一定的間隔,每隔一段時間呼叫這個timer函式,函式push一次然後呼叫update,就可以看到變化過程了。如果把間隔設為0,理論上效果和方法①一樣。(請查timerEvent的用法)解決方法③(較麻煩,執行效率低):在子執行緒裡面處理資料,透過訊號呼叫主執行緒的update。如果資料處理時間太長的話就只能用這種辦法了。具體程式碼就不寫了。
這個和視窗繪製的原理有關,需要從頭說起。1、最基本的原理是:繪製是在主執行緒中完成的。主執行緒是什麼,可以理解為就是main()函式。你寫qt程式肯定知道一個基本用法,main()函式最後需要呼叫QApplication的exec()函式,這個exec()裡面是個死迴圈,每次迴圈呼叫一次QApplication的processEvents(),這個函式負責處理視窗事件、使用者訊息,然後繪製視窗。就是說所有這些事都是在主執行緒中依次完成的,並不是同時進行,所以如果你在主執行緒中處理資料(比如響應按鈕事件),你這個事件處理函式不返回,就不會往下走到繪製這一步。2、update和repaint。可能你已經知道,視窗系統為了提高效能,會盡量減少繪製次數和範圍,所以預設情況下,只有視窗內容顯示出來的時候才進行一次繪製,包括視窗被遮擋的部分重新顯現。update和repaint就是主動通知系統繪製視窗內容。區別在於,update只是在內部資料中做一個標記,要等到主執行緒進行到下一次繪製時才進行繪製,所以多次呼叫update是沒有意義的,只是重複設定繪製標記,並不會馬上進行繪製,而且同樣要等到你的程式碼走完之後走到繪製時才能看到結果。repaint雖然可以立即呼叫到paintEvent,但是光有這個paintEvent還不夠,不跑完整個processEvents,缺少了介面響應,你的視窗就是個死的,看上去仍然不是實時顯示。解決方法①(臨時): 在每次update之後都呼叫一次qApp->processEvents()。這種方法的問題在於,processEvents裡面除了繪製還有事件處理等很多內容,提前呼叫會打亂計劃好的處理順序,這在事件處理複雜的程式中容易導致bug,要小心使用。而且不能控制動畫的速度,因為你不能在主執行緒裡面sleep,那樣會卡死整個介面。解決方法②(推薦):拆分for迴圈,放到timer處理函數里面,timer設定一定的間隔,每隔一段時間呼叫這個timer函式,函式push一次然後呼叫update,就可以看到變化過程了。如果把間隔設為0,理論上效果和方法①一樣。(請查timerEvent的用法)解決方法③(較麻煩,執行效率低):在子執行緒裡面處理資料,透過訊號呼叫主執行緒的update。如果資料處理時間太長的話就只能用這種辦法了。具體程式碼就不寫了。