Invalidate() InvalidateRect() 與 UpdateWindow()

來源:互聯網
上載者:User

標籤:有關   views   繪圖   自動   實現   問題   lte   除了   聲明   

按引:Invalidate在訊息佇列中加入一條WM_PAINT訊息,其無效區為整個客戶區。而UpdateWindow直接發送一個WM_PAINT訊息,其無效區範圍就是訊息佇列中WM_PAINT訊息(最多隻有一條)的無效區。效果很明顯,調用Invalidate之後,螢幕不一定馬上更新,因為WM_PAINT訊息不一定在隊列頭部,而調用UpdateWindow會使WM_PAINT訊息馬上執行的,繞過了訊息佇列。如果你調用Invalidate之後想馬上更新螢幕,那就加上UpdateWindow()這條語句。

 

UpdateData():

    當你使用了ClassWizard建立了控制項和變數之間的聯絡後:當你修改了變數的值,而希望對話方塊控制項更新顯示,就應該在修改變數後調用UpdateData(FALSE);如果你希望知道使用者在對話方塊中到底輸入了什麼,就應該在訪問變數前調用UpdateData(TRUE),將控制項的輸入映射到變數中。

Invalidate():
     該函數的作用是使整個視窗客戶區無效。視窗的客戶區無效意味著需要重繪。例如,如果一個被其它視窗遮住的視窗變成了前台視窗,那麼原來被遮住的部分就是無效的,需要重繪。這時Windows會在應用程式的訊息佇列中放置WM_PAINT訊息。MFC為視窗類別提供了WM_PAINT的訊息處理函數OnPaint,OnPaint負責重繪視窗。視圖類有一些例外,在視圖類的OnPaint函數中調用了OnDraw函數,實際的重繪工作由OnDraw來完成。參數bErase為TRUE時,重繪地區內的背景將被擦除,否則,背景將保持不變。

InvalidateRect():
    該函數的功能與Invalidate基本一樣,不同的是,它是使指定的某個地區無效,需要輸入一個地區,如果參數為NULL,則設定整個視窗為無效區。

UpdateWindow():
     UpdateWindow( )的作用是使視窗立即重繪。調用Invalidate等函數後視窗不會立即重繪,這是由於WM_PAINT訊息的優先順序很低,它需要等訊息佇列中的其它訊息發送完後才能被處理。調用UpdateWindow函數可使WM_PAINT被直接發送到目標視窗,從而導致視窗立即重繪。

UpdateWindow:如果有無效區,則馬上sending a WM_PAINT message到視窗處理過程,不進訊息佇列進行排隊等待,立即重新整理視窗,否則,什麼都不做。 
InvalidateRect:設定無效區,如果為NULL參數,則設定整個視窗為無效區。當應用程式的那個視窗的訊息佇列為空白時,則sending a WM_PAINT message(即使更新地區為空白).在sending a WM_PAINT message的所有InvalidateRect的更新地區會累加。

1:設定無效區 
InvalidateRect 

2:立即重新整理 
UpdateWindow() 

如果不調用 InvalidateRect就調用 UpdateWindow,那麼UpdateWindow什麼都不做。 如果調用 InvalidateRect 後不調用UpdateWindow,則系統會自動在視窗訊息佇列為空白的時候,系統自動發送一WM_PAINT訊息。 

調用UpdateWindow()時將會發送一個WM_PAINT訊息,而應用程式在接收到WM_PAINT訊息後,將自動地調用Invalidate()。所以,在程式碼中,不一定要出現Invalidate()!

UpdateWindow()就是立即發送WM_PAINT訊息,updateWindow要求系統對地區進行立即重繪,其只對聲明為無效的地區起作用,而Invalidate()是聲明無效地區的方式之一。

Invalidate()表示用戶端區域無效,在下次WM_PAINT發生時重繪。而WM_PAINT是由系統進行維護的,每當CWnd的更新地區不為空白,並且在應用程式的視窗訊息佇列中沒有其它訊息時,Windows就發送一條WM_PAINT訊息。

Invalidat最後也是調用InvalidatRect。

RedrawWindow 強制重新整理,會調用WM_PAINT,但如果你強制重新整理的部分不存在就不會調用WM_PAINT。若不帶任何參數,則本視窗全部重新整理。

*****************************************************************************************************************************************

看到有人在網上提出問題,他在Invalidate後面又寫了繪圖的函數但是沒有執行,這是因為invalidate執行過以後就轉到PAINT命令了,所以後面的都沒有顯示。

也終於想通我繪的圖一直在閃啊閃,這是因為我在PAINT裡面用到了Invalidate()函數,所以他不停的自嵌套,導致繪的圖在不停的閃。

總之:Invalidate讓客戶區處於可以重畫的狀態,而UpdateWindow開始重畫,但是它首先需判斷客戶區是否為空白,不空則UpdateWindow不執行,為空白才執行重畫。

*********************************************************************************************************************************************

在重新整理視窗時經常要調用重繪函數MFC提供了三個函數用於視窗重繪
     InvalidateRect(&Rect)
    Invalidate()
     UpdateWindow()
       當需要更新或者重繪視窗時,一般系統會發出兩個訊息WM_PAINT(通知客戶區有變化)和WM_NCPAINT(通知非客戶區有變化)WM_NVPAINT系統會自己搞定WM_PAINT訊息對應的函數是OnPaint(),它是系統預設的接受WM_PAINT訊息的函數,但我們一般在程式中做重繪時都在OnDraw函數中進行的,因為在視圖類ONPAINT函數中調用了ONDRAW函數。
       CView預設的標準的重畫函數
          void CView::OnPaint()
             {  
                   CPaintDC dc(this);   
                   OnPreparDC(&dc);  
                   OnDraw(&dc); //調用了OnDraw

            } 
        上面講到InvalidateRect(&Rect) 和 Invalidate()。兩個函數形式和功能差不多,但Invalidate是使得整個視窗形成無效矩形,而InvalidateRect(&Rect)是使得指定的地區無效。Invalidate()申明無效,等待WM_PAINT訊息以便重繪,隊列中無其他訊息時系統會自動發送。而UpdateWindow()會立即發送WM_PAINT,不過在它發送前,先調用GetUpdateRect(hWnd,NULL,TRUE)看有無可繪製地區,如果沒有則不發送訊息。RedrawWindow()RedrawWindow()則是具有Invalidate()和UpdateWindow()的雙特性。聲明視窗的狀態為無效,並立即更新視窗,立即調用WM_PAINT訊息處理。   
       系統為什麼不在調用Invalidate時發送WM_PAINT訊息呢?又為什麼非要等應用訊息佇列為空白時才發送WM_PAINT訊息呢?這是因為系統把在視窗中的繪製操作當作一種低優先順序的操作,於是儘可能地推後做。不過這樣也有利於提高繪製的效率:兩個WM_PAINT訊息之間通過InvalidateRect和InvaliateRgn使之失效的地區就會被累加起來,然後在一個WM_PAINT訊息中一次得到更新,不僅能避免多次重複地更新同一地區,也最佳化了應用的更新操作。像這種通過InvalidateRect和InvalidateRgn來使視窗地區無效,依賴於系統在合適的時機發送WM_PAINT訊息的機制實際上是一種非同步工作方式,也就是說,在無效化視窗地區和發送WM_PAINT訊息之間是有延遲的;有時候這種延遲並不是我們希望的,這時我們當然可以在無效化視窗地區後利用SendMessage 發送一條WM_PAINT訊息來強制立即重畫,但不如使用Windows GDI為我們提供的更方便和強大的函數:          
        UpdateWindow和RedrawWindow。UpdateWindow會檢查視窗的Update Region,當其不為空白時才發送WM_PAINT訊息;RedrawWindow則給我們更多的控制:是否重畫非客戶區和背景,是否總是發送 WM_PAINT訊息而不管Update Region是否為空白等。BeginPaint和WM_PAINT訊息緊密相關。試一試在WM_PAINT處理函數中不寫BeginPaint會怎樣?程式會像進入了一個死迴圈一樣達到驚人的CPU佔用率,你會發現程式總在處理一個接一個的WM_PAINT訊息。這是因為在通常情況下,當應用收到WM_PAINT訊息時,視窗的Update Region都是非空的(如果為空白就不需要發送WM_PAINT訊息了),BeginPaint的一個作用就是把該Update Region置為空白,這樣如果不調用BeginPaint,視窗的Update Region就一直不為空白,如前所述,系統就會一直發送WM_PAINT訊息。 BeginPaint和WM_ERASEBKGND訊息也有關係。當視窗的Update Region被標誌為需要擦除背景時,BeginPaint會發送WM_ERASEBKGND訊息來重畫背景,同時在其返回資訊裡有一個標誌表明視窗背景是否被重畫過。當我們用InvalidateRect和InvalidateRgn來把指定地區加到Update Region中時,可以設定該地區是否需要被擦除背景,這樣下一個BeginPaint就知道是否需要發送WM_ERASEBKGND訊息了。另外要注意的一點是,BeginPaint只能在WM_PAINT處理函數中使用

 

OnDraw,一般是收到WM_PAINT訊息時調用,所以應用程式一般通過Invalidate產生WM_PAINT訊息來間接調用OnDraw。當表單無效等情況下,window也會產生WM_PAINT訊息,這時OnDraw 也被間接調用。 
OnUpdate 是CView提供的一個方法,一般當文檔修改時調用,應用程式架構在CView::OnInitialUpdate 和CDocument::UpdateAllViews 的預設實現中都會調用 
OnUpdate,OnUpdate的預設實現是通過Invalidate產生WM_PAINT,這時OnDraw又被調用了。 

OnDraw除了你和應用程式架構間接調用外,window還可能間接調用它。 
OnUpdate一般只有你的程式和應用程式架構會調用的。當然它的預設實現你可以改變的

**********************************************************************************************************************

OnInitUpdate是VIEW的初始化 
OnUpdate是文檔多視時,響應其它視圖的改變 
OnDraw和OnPaint都是繪圖。OnPaint調用OnDraw,並且調用OnPrepareDC 
--------------------------------------------------------------- 

Invalidate() InvalidateRect() 與 UpdateWindow()

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.