<menu id="w8yyk"><menu id="w8yyk"></menu></menu>
  • <dd id="w8yyk"><nav id="w8yyk"></nav></dd>
    <menu id="w8yyk"></menu>
    <menu id="w8yyk"><code id="w8yyk"></code></menu>
    <menu id="w8yyk"></menu>
    <xmp id="w8yyk">
    <xmp id="w8yyk"><nav id="w8yyk"></nav>
  • 網站首頁 > 物聯資訊 > 技術分享

    雙緩沖繪圖和窗口控件的繪制――ATL ActiveX 窗口控件生成向導繪制代碼OnDraw的一個錯誤 .

    2016-09-28 00:00:00 廣州睿豐德信息科技有限公司 閱讀
    睿豐德科技 專注RFID識別技術和條碼識別技術與管理軟件的集成項目。質量追溯系統、MES系統、金蝶與條碼系統對接、用友與條碼系統對接

    雙緩沖繪圖和窗口控件的繪制

    ---ATL ActiveX 窗口控件生成向導繪制代碼OnDraw的一個錯誤

     

    cheungmine


    我們通常使用ATL COM組件,生成一個帶窗口的ActiveX控件,然后希望在這個窗口中繪制我們的圖像、圖形等數據,然而ATL向導生成的代碼中包含很多錯誤,下面是其自動向導生成的代碼:

        HRESULT OnDraw(ATL_DRAWINFO& di)
        {
            RECT& rc = *(RECT*)di.prcBounds;
            // 將剪輯區域設置為 di.prcBounds 指定的矩形
            HRGN hRgnOld = NULL;
            if (GetClipRgn(di.hdcDraw, hRgnOld) != 1)
                hRgnOld = NULL;
            bool bSelectOldRgn = false;

            HRGN hRgnNew = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);

            if (hRgnNew != NULL)
            {
                bSelectOldRgn = (SelectClipRgn(di.hdcDraw, hRgnNew) != ERROR);
            }

            Rectangle(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom);
            SetTextAlign(di.hdcDraw, TA_CENTER|TA_BASELINE);
            LPCTSTR pszText = _T("ATL 8.0 : Canvas");
    #ifndef _WIN32_WCE
            TextOut(di.hdcDraw,
                (rc.left + rc.right) / 2,
                (rc.top + rc.bottom) / 2,
                pszText,
                lstrlen(pszText));
    #else
            ExtTextOut(di.hdcDraw,
                (rc.left + rc.right) / 2,
                (rc.top + rc.bottom) / 2,
                ETO_OPAQUE,
                NULL,
                pszText,
                ATL::lstrlen(pszText),
                NULL);
    #endif

            if (bSelectOldRgn)
                SelectClipRgn(di.hdcDraw, hRgnOld);

            return S_OK;
        }


    請注意這里面包含一個錯誤,改正之后的代碼(紅色字體):

        HRESULT OnDraw(ATL_DRAWINFO& di)
        {
            RECT& rc = *(RECT*)di.prcBounds;
            // 將剪輯區域設置為 di.prcBounds 指定的矩形
            HRGN hRgnOld = NULL;
            if (GetClipRgn(di.hdcDraw, hRgnOld) != 1)
                hRgnOld = NULL;
            bool bSelectOldRgn = false;

            HRGN hRgnNew = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);

            if (hRgnNew != NULL)
            {
                bSelectOldRgn = (SelectClipRgn(di.hdcDraw, hRgnNew) != ERROR);
            }

            Rectangle(di.hdcDraw, rc.left, rc.top, rc.right, rc.bottom);
            SetTextAlign(di.hdcDraw, TA_CENTER|TA_BASELINE);
            LPCTSTR pszText = _T("ATL 8.0 : Canvas");
    #ifndef _WIN32_WCE
            TextOut(di.hdcDraw,
                (rc.left + rc.right) / 2,
                (rc.top + rc.bottom) / 2,
                pszText,
                lstrlen(pszText));
    #else
            ExtTextOut(di.hdcDraw,
                (rc.left + rc.right) / 2,
                (rc.top + rc.bottom) / 2,
                ETO_OPAQUE,
                NULL,
                pszText,
                ATL::lstrlen(pszText),
                NULL);
    #endif


            if (bSelectOldRgn)
                SelectClipRgn(di.hdcDraw, hRgnOld);

     

            // 刪除剪輯區域
            ::DeleteObject(hRgnNew);  // Add by cheungmine. MUST!!

     

            return S_OK;
        }

     

    注意其中綠色的代碼,你應該完全注釋掉這種繪制的邏輯,而采用雙緩沖。因此,ATL自動生成的OnDraw代碼是不適合實際的繪圖控件的。下面的代碼是我更改之后的,增加了雙緩沖機制:

        void MyDrawCode (HDC hdc, RECT &rc)

        {

    Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
            SetTextAlign(di.hdcDraw, TA_CENTER|TA_BASELINE);
            LPCTSTR pszText = _T("ATL 8.0 : Canvas");
    #ifndef _WIN32_WCE
            TextOut(hdc,
                (rc.left + rc.right) / 2,
                (rc.top + rc.bottom) / 2,
                pszText,
                lstrlen(pszText));
    #else
            ExtTextOut(hdc,
                (rc.left + rc.right) / 2,
                (rc.top + rc.bottom) / 2,
                ETO_OPAQUE,
                NULL,
                pszText,
                ATL::lstrlen(pszText),
                NULL);
    #endif

        }


        void DbBufferDraw(HDC hdcDraw, RECT &rcClip)
        {
            HDC         hMemDC  = ::CreateCompatibleDC(hdcDraw);             
            ATLASSERT(hMemDC);       
            HBITMAP  hBmpNew = ::CreateCompatibleBitmap(hdcDraw, WidthRect(rcClip), HeightRect(rcClip));           
            ATLASSERT(hBmpNew);
            HBITMAP  hBmpOld = (HBITMAP) ::SelectObject(hMemDC, hBmpNew);

     

              // 添加自己的繪制代碼

            MyDrawCode(hMemDC, rcClip);

            if (IsWindow()) {
                ::BitBlt ( hdcDraw,
                         rcClip.left,
                         rcClip.top,
                         WidthRect(rcClip), HeightRect(rcClip),
                         hMemDC, 
                         rcClip.left,
                         rcClip.top,
                       SRCCOPY );
            }
            else {
                ::BitBlt ( hdcDraw,
                         rcClip.left + m_rcPos.left,
                         rcClip.top  + m_rcPos.top,
                         WidthRect(rcClip), HeightRect(rcClip),
                         hMemDC, 
                         rcClip.left,
                         rcClip.top,
                       SRCCOPY );
            }

            // 釋放 hMemDC
            ::SelectObject(hMemDC, hBmpOld);
            ::DeleteObject(hBmpNew);
            ::DeleteDC(hMemDC);
        }


        HRESULT OnDraw(ATL_DRAWINFO& di)
        {
            RECT& rc = *(RECT*)di.prcBounds;
            // 將剪輯區域設置為 di.prcBounds 指定的矩形
            HRGN hRgnOld = NULL;
            if (GetClipRgn(di.hdcDraw, hRgnOld) != 1)
                hRgnOld = NULL;
            bool bSelectOldRgn = false;

            HRGN hRgnNew = CreateRectRgn(rc.left, rc.top, rc.right, rc.bottom);

            if (hRgnNew != NULL)
            {
                bSelectOldRgn = (SelectClipRgn(di.hdcDraw, hRgnNew) != ERROR);
            }

            // 雙緩沖
         
    DbBufferDraw(di.hdcDraw, rc);


            if (bSelectOldRgn)
                SelectClipRgn(di.hdcDraw, hRgnOld);

            // 刪除剪輯區域
            ::DeleteObject(hRgnNew);  // Add by cheungmine. MUST!!

            return S_OK;
        }

     

    按上面的修改,煩人的閃爍沒了。另外,在OnDarw中,沒必要把全部繪制代碼放入 MyDrawCode 中。因為 MyDrawCode 如果執行時間較長,則 OnDraw會顯得很慢。因此,光是雙緩沖還不夠,因為OnDraw被調用的時候,都是系統激發的,我們只需要把原來保存的繪制圖片直接繪制到hMemDC中即可,也就是, MyDrawCode中不可以如本例所示的那樣,放置實際繪制的代碼,而是只把圖片重新拷貝到hdc上即可,如:

        void MyDrawCode (HDC hdc, RECT &rc)

        {

            m_BkgndMap.CopyTo(hdc, rc);

        }

     

        m_BkgndMap 可以是自己實現的Image或CImage等圖像類。

     

    因此,在一個基本的繪圖系統中,至少需要3個緩沖層次:


    第一層:控件窗口HDC(無窗口控件也是存在HDC的)

    第二層:控件窗口HDC的兼容MemDC,即:HDC hMemDC  = ::CreateCompatibleDC(hdcDraw);

    第三層:后臺圖片HDC包裝類: m_BkgndMap

     

    關于如何創建這樣的ActiveX 窗口控,請看我的相關文章:

    http://blog.csdn.net/cheungmine/archive/2007/10/10/1818913.aspx

     

     

    from:http://blog.csdn.net/ubuntu64fan/article/details/5917979

    RFID管理系統集成商 RFID中間件 條碼系統中間層 物聯網軟件集成
    最近免费观看高清韩国日本大全