WM_PAINT消息小结
WM_PAINT消息小結(jié)
hanlray@gmail.com
Revision: 1.0 Date: 2005/08/14
WM_PAINT是Windows窗口系統(tǒng)中一條重要的消息,應(yīng)用程序通過處理該消息實(shí)現(xiàn)在窗口上的繪制工作。
1.?系統(tǒng)何時(shí)發(fā)送WM_PAINT消息?
系統(tǒng)會(huì)在多個(gè)不同的時(shí)機(jī)發(fā)送WM_PAINT消息:當(dāng)?shù)谝淮蝿?chuàng)建一個(gè)窗口時(shí),當(dāng)改變窗口的大小時(shí),當(dāng)把窗口從另一個(gè)窗口背后移出時(shí),當(dāng)最大化或最小化窗口時(shí),等等,這些動(dòng)作都是由 系統(tǒng)管理的,應(yīng)用只是被動(dòng)地接收該消息,在消息處理函數(shù)中進(jìn)行繪制操作;大多數(shù)的時(shí)候應(yīng)用也需要能夠主動(dòng)引發(fā)窗口中的繪制操作,比如當(dāng)窗口顯示的數(shù)據(jù)改變的時(shí)候,這一般是通過InvalidateRect和 InvalidateRgn函數(shù)來完成的。InvalidateRect和InvalidateRgn把指定的區(qū)域加到窗口的Update Region中,當(dāng)應(yīng)用的消息隊(duì)列沒有其他消息時(shí),如果窗口的Update Region不為空時(shí),系統(tǒng)就會(huì)自動(dòng)產(chǎn)生WM_PAINT消息。
系統(tǒng)為什么不在調(diào)用Invalidate時(shí)發(fā)送WM_PAINT消息呢?又為什么非要等應(yīng)用消息隊(duì)列為空時(shí)才發(fā)送WM_PAINT消息呢?這是因?yàn)橄到y(tǒng)把在窗口中的繪制操作當(dāng)作一種低優(yōu)先級(jí)的操作,于是盡 可能地推后做。不過這樣也有利于提高繪制的效率:兩個(gè)WM_PAINT消息之間通過InvalidateRect和InvaliateRgn使之失效的區(qū)域就會(huì)被累加起來,然后在一個(gè)WM_PAINT消息中一次得到 更新,不僅能避免多次重復(fù)地更新同一區(qū)域,也優(yōu)化了應(yīng)用的更新操作。像這種通過InvalidateRect和InvalidateRgn來使窗口區(qū)域無效,依賴于系統(tǒng)在合適的時(shí)機(jī)發(fā)送WM_PAINT消息的機(jī) 制實(shí)際上是一種異步工作方式,也就是說,在無效化窗口區(qū)域和發(fā)送WM_PAINT消息之間是有延遲的;有時(shí)候這種延遲并不是我們希望的,這時(shí)我們當(dāng)然可以在無效化窗口區(qū)域后利用SendMessage 發(fā)送一條WM_PAINT消息來強(qiáng)制立即重畫,但不如使用Windows GDI為我們提供的更方便和強(qiáng)大的函數(shù):UpdateWindow和RedrawWindow。UpdateWindow會(huì)檢查窗口的Update Region,當(dāng)其不為空時(shí)才發(fā)送WM_PAINT消息;RedrawWindow則給我們更多的控制:是否重畫非客戶區(qū)和背景,是否總是發(fā)送WM_PAINT消息而不管Update Region是否為空等。
2.?BeginPaint
BeginPaint和WM_PAINT消息緊密相關(guān)。試一試在WM_PAINT處理函數(shù)中不寫B(tài)eginPaint會(huì)怎樣?程序會(huì)像進(jìn)入了一個(gè)死循環(huán)一樣達(dá)到驚人的CPU占用率,你會(huì)發(fā)現(xiàn)程序總在處理一個(gè)接 一個(gè)的WM_PAINT消息。這是因?yàn)樵谕ǔG闆r下,當(dāng)應(yīng)用收到WM_PAINT消息時(shí),窗口的Update Region都是非空的(如果為空就不需要發(fā)送WM_PAINT消息了),BeginPaint的一個(gè)作用就是把該Update Region置為空,這樣如果不調(diào)用BeginPaint,窗口的Update Region就一直不為空,如前所述,系統(tǒng)就會(huì)一直發(fā)送WM_PAINT消息。
BeginPaint和WM_ERASEBKGND消息也有關(guān)系。當(dāng)窗口的Update Region被標(biāo)志為需要擦除背景時(shí),BeginPaint會(huì)發(fā)送WM_ERASEBKGND消息來重畫背景,同時(shí)在其返回信息里有一個(gè)標(biāo)志表明窗口背景是否被重畫過。當(dāng)我們用InvalidateRect和InvalidateRgn來把指定區(qū)域加到Update Region中時(shí),可以設(shè)置該區(qū)域是否需要被擦除背景,這樣下一個(gè)BeginPaint就知道是否需要發(fā)送WM_ERASEBKGND消息了。
另外要注意的一點(diǎn)是,BeginPaint只能在WM_PAINT處理函數(shù)中使用。
總結(jié)
以上是生活随笔為你收集整理的WM_PAINT消息小结的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 基于VC++的GDI常用坐标系统及应用
- 下一篇: GDI中的坐标映射问题