国产一级a片免费看高清,亚洲熟女中文字幕在线视频,黄三级高清在线播放,免费黄色视频在线看

打開APP
userphoto
未登錄

開通VIP,暢享免費電子書等14項超值服

開通VIP
VC窗口刷新InvalidateRect和UpdateWindow
WM_PAINT這個重要的消息

  The WM_PAINT message is generated by the system and should not be sent by an application.The system sends this message when there are no other messages in the application's message queue

  也就是說WM_PAINT消息是由系統(tǒng)產(chǎn)生,非要等應用程序的消息隊列為空時才發(fā)送WM_PAINT消息,并且該消息不應該被程序(自己寫代碼用SendMessage)來發(fā)送。

  當調(diào)用UpdateWindow函數(shù),或者是Window檢測到窗口被覆蓋的地方需要恢復的時候,比如,第一次創(chuàng)建窗口,改變了窗口的大小,最大化,最小化等等(其實這些事件發(fā)生時會調(diào)用UpdateWindow函數(shù),由該函數(shù)發(fā)送WM_PAINT消息),它會向用戶程序發(fā)送一個WM_PAINT消息。窗口過程收到WM_PAINT消息后,并不代表整個客戶區(qū)都需要被刷新,有可能客戶區(qū)被覆蓋的區(qū)域只有一小塊,這個區(qū)域叫做“無效區(qū)域”,程序只需要更新這個區(qū)域。與WM_TIMER消息類似,WM_PAINT消息也是一個低級別的消息,雖然它不會像WM_TIMER消息一樣被丟棄,但Windows總是在消息循環(huán)空的時候才把WM_PAINT放入其中。

  無效區(qū)域的坐標并不附帶在WM_PAINT消息的參數(shù)中,在程序中有其他方法可以獲取。WM_PAINT消息只是通知程序有個區(qū)域需要更新而已,所以Windows也不會同時將兩條WM_PAINT消息放入消息循環(huán)中。當Windows要放入一條WM_PAINT消息的時候,如果發(fā)現(xiàn)已經(jīng)存在一個無效區(qū)域了,那么它只需要把新舊兩個無效區(qū)域合并計算出一個無效區(qū)域就可以了,消息循環(huán)中還是只需要一條WM_PAINT消息。

  實際上,Windows為每個窗口維護一個“繪圖信息結(jié)構(gòu)”,無效區(qū)域的坐標就在其中,每當消息循環(huán)空的時候,如果Windows發(fā)現(xiàn)存在一個無效區(qū)域,就會放入一個WM_PAINT消息。那么“繪圖信息結(jié)構(gòu)”怎么獲取呢?BeginPaint函數(shù)的第二個參數(shù)就是一個繪圖信息結(jié)構(gòu)的緩沖區(qū)地址,windows會在這里返回繪圖信息結(jié)構(gòu),結(jié)構(gòu)中包含了無效區(qū)域的位置和大小,繪圖信息結(jié)構(gòu)的定義如下:

typedef struct tagPAINTSTRUCT { // ps 
    HDC   hdc; 
    BOOL fErase; 
    RECT rcPaint; 
    BOOL fRestore; 
    BOOL fIncUpdate; 
    BYTE rgbReserved[32]; 
} PAINTSTRUCT; 

  其中hdc字段是窗口的設(shè)備環(huán)境句柄,rcPaint字段是一個RECT結(jié)構(gòu),它指定了無效區(qū)域矩形的對角頂點(如果開始有一個((0,0),(40,40)),現(xiàn)在又來一個((20,20),(60,30)),那么拼接后就是((0,0),(60,40))),fErase字段如果為非零值,表示W(wǎng)indows在發(fā)送WM_PAINT消息前已經(jīng)使用背景色擦除了無效區(qū)域,后面3個字段是Windows內(nèi)部使用的,應用程序不必去理會他們。

  在某些情況下,顯示區(qū)域的一部分被臨時覆蓋,Windows試圖保存一個顯示區(qū)域,并在以后恢復它,但這不一定能成功。Windows可能發(fā)送WM_PAINT消息:Windows擦除覆蓋了部分窗口的對話框或消息框;菜單下拉出來,然后被釋放;顯示工具提示消息。

  在某些情況下,Windows總是一定保存它所覆蓋的顯示區(qū)域,然后恢復它。這些情況是:鼠標光標穿越顯示區(qū)域;圖標拖過顯示區(qū)域。

  有時候應用也需要能夠主動引發(fā)窗口中的繪制操作,比如當窗口顯示的數(shù)據(jù)改變的時候,這一般是通過InvalidateRect和 InvalidateRgn函數(shù)來完成的。InvalidateRect和InvalidateRgn把指定的區(qū)域加到窗口的Update Region中,當應用的消息隊列沒有其他消息時,如果窗口的Update Region不為空時,系統(tǒng)就會自動產(chǎn)生WM_PAINT消息。

  系統(tǒng)為什么不在調(diào)用Invalidate時發(fā)送WM_PAINT消息呢?又為什么非要等應用消息隊列為空時才發(fā)送WM_PAINT消息呢?這是因為系統(tǒng)把在窗口中的繪制操作當作一種低優(yōu)先級的操作,于是盡 可能地推后做。不過這樣也有利于提高繪制的效率:兩個WM_PAINT消息之間通過InvalidateRect和InvaliateRgn使之失效的區(qū)域就會被累加起來,然后在一個WM_PAINT消息中一次得到 更新,不僅能避免多次重復地更新同一區(qū)域,也優(yōu)化了應用的更新操作。像這種通過InvalidateRect和InvalidateRgn來使窗口區(qū)域無效,依賴于系統(tǒng)在合適的時機發(fā)送WM_PAINT消息的機 制實際上是一種異步工作方式,也就是說,在無效化窗口區(qū)域和發(fā)送WM_PAINT消息之間是有延遲的;有時候這種延遲并不是我們希望的,這時我們當然可以在無效化窗口區(qū)域后利用SendMessage 發(fā)送一條WM_PAINT消息來強制立即重畫,但不如使用Windows GDI為我們提供的更方便和強大的函數(shù):UpdateWindow和RedrawWindow。UpdateWindow會檢查窗口的Update Region,當其不為空時才發(fā)送WM_PAINT消息;RedrawWindow則給我們更多的控制:是否重畫非客戶區(qū)和背景,是否總是發(fā)送WM_PAINT消息而不管Update Region是否為空等。

  BeginPaint

  今天在處理WM_PAINT消息時產(chǎn)生了一個低級的錯誤,并搞的我花了快一個小時才找到原因。我在處理消息時,沒有使用BeginPaint和EndPaint這對函數(shù),結(jié)果我其余的消息彈不出來,窗口拖動時,不停閃爍(其實那就是重繪)。后來還是在MSDN上找到了答案,現(xiàn)將原話貼出來。(在MSDN的The WM_PAINT Message標題中)

  BeginPaint sets the update region of a window to NULL. This clears the region, preventing it fromgenerating subsequent WM_PAINT messages. If an application processes a WM_PAINT message but does not call BeginPaint or otherwise clear the update region, the application continues to receive WM_PAINT messages as long as the region is not empty. In all cases, an application must clear the update region before returning from the WM_PAINT message. 
  BeginPaint函數(shù)的作用就是將窗口需要重繪的區(qū)域設(shè)置為空(也就是Update Region置空)。在正常情況下,我們接收到了WM_PAINT消息后,窗口的Update Region都是非空的(如果為空就不需要發(fā)送WM_PAINT消息了)。而當你響應這個消息的時候又不調(diào)用BeginPaint來清空,窗口的Update Region就一直是非空的,系統(tǒng)就會一直發(fā)送WM_PAINT消息。這樣就形成了一個處理WM_PAINT消息的死循環(huán)。

  BeginPaint和WM_PAINT消息緊密相關(guān)。試一試在WM_PAINT處理函數(shù)中不寫B(tài)eginPaint會怎樣?程序會像進入了一個死循環(huán)一樣達到驚人的CPU占用率,你會發(fā)現(xiàn)程序總在處理一個接 一個的WM_PAINT消息。這是因為在通常情況下,當應用收到WM_PAINT消息時,窗口的Update Region都是非空的(如果為空就不需要發(fā)送WM_PAINT消息了),BeginPaint的一個作用就是把該Update Region置為空,這樣如果不調(diào)用BeginPaint,窗口的Update Region就一直不為空,如前所述,系統(tǒng)就會一直發(fā)送WM_PAINT消息。

  BeginPaint和WM_ERASEBKGND消息也有關(guān)系。當窗口的Update Region被標志為需要擦除背景時,BeginPaint會發(fā)送WM_ERASEBKGND消息來重畫背景,同時在其返回信息里有一個標志表明窗口背景是否被重畫過。當我們用InvalidateRect和InvalidateRgn來把指定區(qū)域加到Update Region中時,可以設(shè)置該區(qū)域是否需要被擦除背景,這樣下一個BeginPaint就知道是否需要發(fā)送WM_ERASEBKGND消息了。

  當然關(guān)于 WM_PAINT消息還有很多的知識需要學習。另外要注意的一點是,BeginPaint只能在WM_PAINT處理函數(shù)中使用,并且在調(diào)用了BeginPaint函數(shù)后,不要忘記了調(diào)用EndPaint函數(shù),他們可是一對的。

  重畫函數(shù) InvalidateRect,Invalidate,UpdateWindow, RedrawWindow

  InvalidateRect(部分區(qū)域) 和Invalidate(整個窗口) 僅僅是用來設(shè)置無效區(qū)域,但是并不重繪窗口。

  UpdateWindow 檢查窗口有無無效區(qū)域,如果有,則立即發(fā)送一個WM_PAINT 消息給窗口并立即重畫?!?/font>

  RedrawWindow相當于先調(diào)用InvalidateRect,緊接著又調(diào)用UpdateWindow,此外RedrawWindow還提供了一些前兩者沒法做到的功能。

      如果不調(diào)用 InvalidateRect就調(diào)用 UpdateWindow,那么UpdateWindow什么都不做,因為沒有無效區(qū)域。如果調(diào)用 InvalidateRect 后不調(diào)用UpdateWindow,則系統(tǒng)會自動在窗口消息隊列為空的時候,系統(tǒng)自動發(fā)送一WM_PAINT消息。

本站僅提供存儲服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊舉報。
打開APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
生活服務(wù)
分享 收藏 導長圖 關(guān)注 下載文章
綁定賬號成功
后續(xù)可登錄賬號暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點擊這里聯(lián)系客服!

聯(lián)系客服