2013-07-31 70 views
1

我有幾個關於在MFC中繪製筆畫的問題。假設類CStroke已被預先聲明。示例代碼如下所示。渲染到設備上下文時的資源管理(CDC/HDC)

BOOL CStroke::DrawStroke(CDC* pDC) 
{ 
    CPen penStroke; 
    if (!penStroke.CreatePen(PS_SOLID, m_nPenWidth, m_color)) 
     return FALSE; 
    CPen *pOldPen = pDC->SelectObject(&penStroke); 
    pDC->MoveTo(m_pointArray[0]); 

    for(int i = 0; i < m_pointArray.GetSize(); i++) 
    { 
     pDC->LineTo(m_pointArray[i]); 
    } 

    pDC->SelectObject(pOldPen); 
    return TRUE; 
} 

我的問題是:

  1. 爲什麼我需要pOldPen?
  2. 爲什麼我需要用pDC->SelectObject(pOldPen)來選擇pOldPen?
+0

很簡單:把筆改回原來的樣子。 –

+0

在繪圖過程中是否更換了筆? – Trista

+0

是: - > penStroke.CreatePen(PS_SOLID,m_nPenWidth,m_color) –

回答

1

簡短的回答:

  1. 爲什麼我需要pOldPen

    因爲你欠你的來電者。它不是作爲禮物。

  2. 爲什麼我最終需要用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