雙緩沖繪圖和窗口控件的繪制――ATL ActiveX 窗口控件生成向導繪制代碼OnDraw的一個錯誤 .
雙緩沖繪圖和窗口控件的繪制
---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中間件 條碼系統中間層 物聯網軟件集成