簡短的回答:
爲什麼我需要pOldPen
?
因爲你欠你的來電者。它不是作爲禮物。
爲什麼我最終需要用pDC->SelectObject(pOldPen)
來選擇pOldPen
?
因爲選擇另一個資源到DC是從DC中選擇當前資源的唯一方法。
的設備上下文代表您選擇它們爲直流致電SelectObject
時使用GDI資源。在任何時候,一個DC中只有一個graphics object(筆,畫筆,位圖等)被選中。但是,它不會爲您管理資源。資源管理留給應用程序。
不幸的是,上面的MFC實現隱藏了關於資源管理的一個重要細節。翻譯的代碼到一個純WinAPI的實施,將使其更清楚什麼CPen
躲在:
BOOL CStroke::DrawStroke(HDC hDC)
{
// Create a new pen resource
HPEN penStroke = CreatePen(PS_SOLID, m_nPenWidth, m_color);
if (penStroke == NULL)
return FALSE;
// Select it into the device context
HPEN oldPen = static_cast<HPEN>(SelectObject(hDC, &penStroke));
// Render strokes
if (m_pointArray.GetSize() > 0) // bugfix *
{
pDC->MoveTo(m_pointArray[0]);
for(int i = 1; i < m_pointArray.GetSize(); i++) // bugfix **
{
pDC->LineTo(m_pointArray[i]);
}
}
// Select pen out of DC
HPEN penCreatedAbove = static_cast<HPEN>(SelectObject(hDC, oldPen));
// Clean up our resource (this is what CPen::~CPen() hides)
DeleteObject(penCreatedAbove)
return TRUE;
}
由於上面的代碼創建一個圖形對象(見CreatePen
)是負責釋放它,以及相關的資源。要釋放資源,應用程序將調用DeleteObject
。此API調用具有以下要求:
不要刪除圖形對象(筆或刷子),同時它仍然是 選擇成直流。
爲了滿足先決條件在上面的代碼中創建的筆需要選擇出來的DC的。這是對SelectObject(hDC, oldPen)
的呼籲。 (我做了這個更加明顯通過引入一個變量來存儲返回值。)
既然你已經選擇東西成DC拉你的資源回來了,也有極少數的選擇真的:唯一的圖形對象你在這一點上既不擁有也不得不銷燬的是oldPen
。這也保證了你可以嵌套渲染代碼,如以下僞代碼所示:
HPEN bestPenEver = CreatePen();
HPEN oldPen = SelectObject(bestPenEver);
// Do some painting with bestPenEver
call DrawStroke()
// Do some more painting with bestPenEver
SelectObject(oldPen);
DeleteObject(bestPenEver);
的完整性和排隊這裏的MFC代碼這個實現是相關MFC-實現:
CPen::CreatePen(int nPenStyle, int nWidth, COLORREF crColor)
{ return Attach(::CreatePen(nPenStyle, nWidth, crColor)); }
CPen penStroke
是一個自動變量,所以它的析構函數在控制離開封閉塊時運行(即當DrawStroke
返回時)。析構函數調用它的基類實現CGdiObject::DeleteObject
如下:
BOOL CGdiObject::DeleteObject()
{
if (m_hObject == NULL)
return FALSE;
return ::DeleteObject(Detach());
}
bug修正*不再訪問一個空序列的第一個元素。
bugfix **第一個元素已被用於MoveTo
。
很簡單:把筆改回原來的樣子。 –
在繪圖過程中是否更換了筆? – Trista
是: - > penStroke.CreatePen(PS_SOLID,m_nPenWidth,m_color) –