• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            天下

            記錄修行的印記

            有關窗口繪制的消息整理

            窗口繪制有關的消息整理
            WM_PAINTWM_NCPAINTWM_ERASEBKGND

            WM_PAINT
            WM_PAINT是Windows窗口系統中一條重要的消息,應用程序通過處理該消息實現在窗口上的繪制工作。

            WM_NCPAINT
            當窗口客戶區以外的部分(如窗口標題欄、菜單欄等)需要需要重畫時,系統向程序發出該消息。因標準窗口的客戶區以外部分為窗口必需部分,因而該消息將默認被發送到DefWindowProc函數進行默認處理。程序可通過截獲該消息來實現窗口其他部分的自定義繪制。

            WM_ERASEBKGND

            The WM_ERASEBKGND message is sent when the window background must be erased (for example, when a window is resized). The message is sent to prepare an invalidated portion of a window for painting.

            一、WM_PAINT消息
            在系統繪制窗口時向程序發出WM_PAINT消息。程序在接收到WM_PAINT消息后調用BeginPaint函數獲取當前的Device Context進行繪圖操作,繪圖完畢后使用EndPaint釋放Device Context。

            1. 系統何時發送WM_PAINT消息?

            系統會在多個不同的時機發送WM_PAINT消息:當第一次創建一個窗口時,當改變窗口的大小時,當把窗口從另一個窗口背后移出時,當最大化或最小化窗口時,等等,這些動作都是由 系統管理的,應用只是被動地接收該消息,在消息處理函數中進行繪制操作;大多數的時候應用也需要能夠主動引發窗口中的繪制操作,比如當窗口顯示的數據改變的時候,這一般是通過InvalidateRect和 InvalidateRgn函數來完成的。InvalidateRect和InvalidateRgn把指定的區域加到窗口的Update Region中,當應用的消息隊列沒有其他消息時,如果窗口的Update Region不為空時,系統就會自動產生WM_PAINT消息。

            系統為什么不在調用Invalidate時發送WM_PAINT消息呢?又為什么非要等應用消息隊列為空時才發送WM_PAINT消息呢?這是因為系統把在窗口中的繪制操作當作一種低優先級的操作,于是盡 可能地推后做。不過這樣也有利于提高繪制的效率:兩個WM_PAINT消息之間通過InvalidateRect和InvaliateRgn使之失效的區域就會被累加起來,然后在一個WM_PAINT消息中一次得到 更新,不僅能避免多次重復地更新同一區域,也優化了應用的更新操作。

            像這種通過InvalidateRect和InvalidateRgn來使窗口區域無效,依賴于系統在合適的時機發送WM_PAINT消息的機 制實際上是一種異步工作方式,也就是說,在無效化窗口區域和發送WM_PAINT消息之間是有延遲的;
            //有時候這種延遲并不是我們希望的,這時我們當然可以在無效化窗口區域后利用SendMessage 發送一條WM_PAINT消息來強制立即重畫。
            注解:
            SendMessage會block到被發送的消息被處理完才返回,但是WM_PAINT消息的處理時間又是用戶不可控制的:“GetMessage returns the WM_PAINT message when there are no other messages in the application's message queue, and DispatchMessage sends the message to the appropriate window procedure. ”(MSDN原文),那么也就是說,你調用SendMessage之后,這個方法需要等待多長時間才能返回是不可控制的。所以MSDN不推薦用戶直接發送WM_PAINT消息:“The WM_PAINT message is generated by the system and should not be sent by an application”
            但不如使用Windows GDI為我們提供的更方便和強大的函數:
            UpdateWindow和RedrawWindow。UpdateWindow會檢查窗口的Update Region,當其不為空時才發送WM_PAINT消息;
            RedrawWindow則給我們更多的控制:是否重畫非客戶區和背景,是否總是發送WM_PAINT消息而不管Update Region是否為空等。

            WM_PAINT觸發機制
            如果WM_PAINT不是由InvalidateRect或InvalidateRgn產生時,先發WM_ERASEBKGND,再發WM_PAINT
            如果WM_PAINT是由InvalidateRect或InvalidateRgn產生時,則先發WM_PAINT,
            然后beginPaint()再根據Invalidate的bErase參數(重畫背景)來決定是否發WM_ERASEBKGND消息


            當WM_PAINT不是由InvalidateRect產生時,即由最大化,最小化等產生時,或者移動產生(移動有時只會產生WM_ERASEBKGND消息)系統先發送WM_ERASEBKGND消息,再發送WM_PAINT消息.
            當WM_PAINT由InvalidateRect()產生時,先發送WM_PAINT消息(異步),如果InvalidateRect的bErase為TRUE,BeginPaint檢查到更新區域需要刪除背景,向窗口發送一個WM_ERASEBKGND
            消息


            二、WM_ERASEBKGND消息
            Parameters
            wParam
            Handle to the device context.

            lParam
            This parameter is not used.

            Return Value
            An application should return nonzero if it erases the background; otherwise, it should return zero.
            也就是說WM_ERASEBKGND消息重繪了背景,應該返回非0值,否則返回0;


            Remarks
            The DefWindowProc function erases the background by using the class background brush specified by the hbrBackground member of the WNDCLASS structure. If hbrBackground is NULL, the application should process the WM_ERASEBKGND message and erase the background.

            An application should return nonzero in response to WM_ERASEBKGND if it processes the message and erases the background; this indicates that no further erasing is required. If the application returns zero, the window will remain marked for erasing. (Typically, this indicates that the fErase member of the PAINTSTRUCT structure will be TRUE.)

            補充:
            DefWindowProc(hWnd, message, wParam, lParam)處理WM_ERASEBKGND消息時默認用下面的畫刷清除背景
            wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);

            三、WM_NCPAINT消息
            The WM_NCPAINT message is sent to a window when its frame must be painted.

            A window receives this message through its WindowProc function.

            LRESULT CALLBACK WindowProc(
              HWND hwnd,       // handle to window
              UINT uMsg,       // WM_NCPAINT
              WPARAM wParam,   // handle to update region (HRGN)
              LPARAM lParam    // not used
            );
            Parameters
            wParam
            Handle to the update region of the window. The update region is clipped to the window frame. When wParam is 1, the entire window frame needs to be updated.
            lParam
            This parameter is not used.
            Return Values
            An application returns zero if it processes this message.

            Remarks
            The DefWindowProc function paints the window frame.

            An application can intercept the WM_NCPAINT message and paint its own custom window frame. The clipping region for a window is always rectangular, even if the shape of the frame is altered.

            The wParam value can be passed to GetDCEx as in the following example.

            case WM_NCPAINT:
            {
                HDC hdc;
                hdc = GetDCEx(hwnd, (HRGN)wParam, DCX_WINDOW|DCX_INTERSECTRGN);
                // Paint into this DC
                ReleaseDC(hwnd, hdc);
            }

            四、PAINTSTRUCT結構體
            The PAINTSTRUCT structure contains information for an application. This information can be used to paint the client area of a window owned by that application.

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

            Members
            hdc
            Handle to the display DC to be used for painting.

            fErase
            Specifies whether the background must be erased. This value is nonzero if the application should erase the background. The application is responsible for erasing the background if a window class is created without a background brush. For more information, see the description of the hbrBackground member of the WNDCLASS structure.

            rcPaint
            Specifies a RECT structure that specifies the upper left and lower right corners of the rectangle in which the painting is requested, in device units relative to the upper-left corner of the client area.

            五、相關函數
            1) BeginPaint
            The BeginPaint function prepares the specified window for painting and fills a PAINTSTRUCT structure with information about the painting.
            HDC BeginPaint(
              HWND hwnd,            // handle to window
              LPPAINTSTRUCT lpPaint // paint information
            );
            Parameters
            hwnd
            [in] Handle to the window to be repainted.
            lpPaint
            [out] Pointer to the PAINTSTRUCT structure that will receive painting information.
            Return Values
            If the function succeeds, the return value is the handle to a display device context for the specified window.
            If the function fails, the return value is NULL, indicating that no display device context is available.
            Windows NT/2000/XP: To get extended error information, call GetLastError.

            Remarks
            The BeginPaint function automatically sets the clipping region of the device context to exclude any area outside the update region. The update region is set by the InvalidateRect or InvalidateRgn function and by the system after sizing, moving, creating, scrolling, or any other operation that affects the client area. If the update region is marked for erasing, BeginPaint sends a WM_ERASEBKGND message to the window.

            An application should not call BeginPaint except in response to a WM_PAINT message. Each call to BeginPaint must have a corresponding call to the EndPaint function.

            If the caret is in the area to be painted, BeginPaint automatically hides the caret to prevent it from being erased.

            If the window's class has a background brush, BeginPaint uses that brush to erase the background of the update region before returning.

            BeginPaint
            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消息了。
            如果處理WM_ERASEBKGND時返回TRUE,BeginPaint標記ps.fErase為FALSE,
            如果處理WM_ERASEBKGND消息時返回FALSE,BeginPaint標記ps.fErase 為TRUE.

            另外要注意的一點是,BeginPaint只能在WM_PAINT處理函數中使用。


            2)InvalidateRect
               InvalidateRect只是增加重繪區域,在下次WM_PAINT的時候才生效,InvalidateRect函數中的參數TRUE表示系統會在你畫之前用背景色將所選區域覆蓋一次,默認背景色為白色,可以通過設置BRUSH來改變背景色。

               InvalidateRect(hWnd,
            &rect,TRUE);向hWnd窗體發出WM_PAINT的消息,強制客戶區域重繪制,rect是你指定要刷新的區域,此區域外的客戶區域不被重繪,這樣防止客戶區域的一個局部的改動,而導致整個客戶區域重繪而導致閃爍,如果最后的參數為TRUE,則還向窗體發送WM_ERASEBKGND消息,使背景重繪,當然在客戶區域重繪之前。

            (3)UpdateWindow
               UpdateWindow只向窗體發送WM_PAINT消息,在發送之前判斷GetUpdateRect(hWnd,NULL,TRUE)看有無可繪制的客戶區域,如果沒有,則不發送WM_PAINT。如果希望立即刷新無效區域,可以在調用InvalidateRect之后調用UpdateWindow,如果客戶區的任一部分無效,則UpdateWindow將導致Windows用WM_PAINT消息調用窗口過程(如果整個客戶區有效,則不調用窗口過程)。這一WM_PAINT消息不進入消息隊列,直接由WINDOWS調用窗口過程。窗口過程完成刷新以后立刻退出,WINDOWS將控制返回給程序中UpdateWindow調用之后的語句。(windows程序設計第5版 P98)

            4)EndPaint
            The EndPaint function marks the end of painting in the specified window. This function is required for each call to the BeginPaint function, but only after painting is complete.

            BOOL EndPaint(
              HWND hWnd,                  // handle to window
              CONST PAINTSTRUCT *lpPaint  // paint data
            );
            Parameters
            hWnd
            [in] Handle to the window that has been repainted.
            lpPaint
            [in] Pointer to a PAINTSTRUCT structure that contains the painting information retrieved by BeginPaint.
            Return Values
            The return value is always nonzero.

            Remarks
            If the caret was hidden by BeginPaint, EndPaint restores the caret to the screen.


            posted on 2011-04-15 11:46 天下 閱讀(2282) 評論(1)  編輯 收藏 引用 所屬分類: Win32

            評論

            # re: 有關窗口繪制的消息整理 2012-06-15 14:30 開通

            很好。
            能再詳細點就更好了  回復  更多評論   

            <2012年4月>
            25262728293031
            1234567
            891011121314
            15161718192021
            22232425262728
            293012345

            導航

            統計

            常用鏈接

            留言簿(4)

            隨筆分類(378)

            隨筆檔案(329)

            鏈接

            最新隨筆

            搜索

            最新評論

            少妇熟女久久综合网色欲| 国产成人综合久久久久久| 精品国产乱码久久久久久呢| 精产国品久久一二三产区区别| 亚洲女久久久噜噜噜熟女| 国产高潮国产高潮久久久91 | 精品无码久久久久久午夜| 偷窥少妇久久久久久久久| 色综合合久久天天综合绕视看| 国产精品免费久久| 久久久精品人妻一区二区三区蜜桃| 欧洲人妻丰满av无码久久不卡 | 情人伊人久久综合亚洲| 亚洲国产精品综合久久网络| 久久精品毛片免费观看| 亚洲欧美另类日本久久国产真实乱对白 | 亚洲国产美女精品久久久久∴| 99久久夜色精品国产网站| 亚洲狠狠婷婷综合久久蜜芽| 久久99热这里只有精品国产 | 亚洲色婷婷综合久久| 久久精品无码午夜福利理论片| 日韩亚洲国产综合久久久| 99国产欧美久久久精品蜜芽 | 亚洲中文字幕无码久久精品1| 一本伊大人香蕉久久网手机| 国产精品99久久免费观看| 狠狠精品久久久无码中文字幕| 欧美亚洲另类久久综合婷婷 | 国产AⅤ精品一区二区三区久久| 亚洲精品乱码久久久久久蜜桃图片| 亚洲国产成人久久精品99| 94久久国产乱子伦精品免费| 69久久夜色精品国产69| 久久亚洲精品成人AV| 一本一本久久aa综合精品| 中文字幕久久久久人妻| 久久久精品2019免费观看| 久久久无码人妻精品无码| 国产成人久久激情91| 一本久久a久久精品综合夜夜|