MFC和Win32之三___CGdiObject类和windows Gdi对象
?
小結(jié):
前面講到的windows窗口對象,在windows下用句柄來代表之,并且用了一個數(shù)據(jù)結(jié)構(gòu)WNDCLASS(窗口類)來描述之。同理,windows的Gdi對象也有一些句柄來代表之(比如hPen等),同時也有一個數(shù)據(jù)結(jié)構(gòu)來描述之,即設(shè)備描述表(Device Context),而且其本身也有句柄,因此也可以看作是windows的一個對象。
由于設(shè)備描述表這個數(shù)據(jù)結(jié)果不像WNDCLASS那樣單一,因為他要描述多個繪圖設(shè)備。所以MFC同時也封裝設(shè)備描述表,并用幾個類來代表不同的設(shè)備描述表,他們的基類都是CDC。這里特別講到了,當(dāng)直接使用CDC這個基類的情況,可以看出CDC這個基類的構(gòu)造函數(shù)中并沒有創(chuàng)建任何的設(shè)備描述表,所以要使用時創(chuàng)建一個設(shè)備描述表(堆上,棧上都可以)。同時這個基類的析構(gòu)函數(shù)不是虛擬的,所以不必?fù)?dān)心該對象釋放時,它的句柄沒有釋放。
windows的Gdi對象,就是通過CGdiObject來封裝。
?
?
?
?
?
?
?
?
?
?
?
?
當(dāng)一個應(yīng)用程序使用GDI函數(shù)時,必須先裝入特定的設(shè)備驅(qū)動程序,然后為繪制窗口準(zhǔn)備設(shè)備描述表,比如指定線的寬度和顏色、刷子的樣式和顏色、字體、剪裁區(qū)域等等。不像其他Win32結(jié)構(gòu),設(shè)備描述表不能被直接訪問,只能通過系列Win32函數(shù)來間接地操作。
如同Windows“窗口類”一樣,設(shè)備描述表也是一種Windows數(shù)據(jù)結(jié)構(gòu),用來描述繪制窗口所需要的信息。它定義了一個坐標(biāo)映射模式、一組GDI圖形對象及其屬性。這些GDI對象包括用于畫線的筆,繪圖、填圖的刷子,位圖,調(diào)色板,剪裁區(qū)域,及路徑(Path)。
表2-2列出了設(shè)備描述表的結(jié)構(gòu)和各項缺省值,表2-3列出了設(shè)備描述表的類型,表2-4顯示設(shè)備描述表的類型。
表2-2 設(shè)備描述表的結(jié)構(gòu)
| 屬性 | 缺省值 |
| Background color | Background color setting from Windows Control Panel (typically, white) |
| Background mode | OPAQUE |
| Bitmap | None |
| Brush | WHITE_BRUSH |
| Brush origin | (0,0) |
| Clipping region | Entire window or client area with the update region clipped, as appropriate. Child and pop-up windows in the client area may also be clipped |
| Palette | DEFAULT_PALETTE |
| Current pen position | (0,0) |
| Device origin | Upper left corner of the window or the client area |
| Drawing mode | R2_COPYPEN |
| Font | SYSTEM_FONT (SYSTEM_FIXED_FONT for applications written to run with Windows versions 3.0 and earlier) |
| Intercharacter spacing | 0 |
| Mapping mode | MM_TEXT |
| Pen | BLACK_PEN |
| Polygon-fill mode | ALTERNATE |
| Stretch mode | BLACKONWHITE |
| Text color | Text color setting from Control Panel (typically, black) |
| Viewport extent | (1,1) |
| Viewport origin | (0,0) |
| Window extent | (1,1) |
| Window origin | (0,0) |
表2-3 設(shè)備描述表的分類
| Display | 顯示設(shè)備描述表,提供對視頻顯示設(shè)備上的繪制操作的支持 |
| Printer | 打印設(shè)備描述表,提供對打印機(jī)、繪圖儀設(shè)備上的繪制操作的支持 |
| Memory | 內(nèi)存設(shè)備描述表,提供對位圖操作的支持 |
| Information | 信息設(shè)備描述表,提供對操作設(shè)備信息獲取的支持 |
表2-3中的顯示設(shè)備描述表又分三種類型,如表2-4所示。
表2-4 顯示設(shè)備描述表的分類
| 名稱 | 特點 | 功能 |
| Class Device Contexts | 提供對Win16的向后兼容 | |
| Common Device Contexts | 在Windows系統(tǒng)的高速緩沖區(qū),數(shù)量有限 | Applicaion獲取設(shè)備描述表時,Windows用缺省值初始化該設(shè)備描述表,Application使用它完成繪制操作,然后釋放 |
| Private Device Contexts | 沒有數(shù)量限制,用完不需釋放一次獲取,多次使用 | 多次使用過程中,每次設(shè)備描述表屬性的任何修改或變化都會被保存,以支持快速繪制 |
?
?
(1)使用設(shè)備描述表的步驟
要使用設(shè)備描述表,一般有如下步驟:
?
- 獲取或者創(chuàng)建設(shè)備描述表;
?
?
- 必要的話,改變設(shè)備描述表的屬性;
?
?
- 使用設(shè)備描述表完成繪制操作;
?
?
- 釋放或刪除設(shè)備描述表。
?
?
?
Common設(shè)備描述表通過::GetDC,::GetDCEx,::BeginPaint來獲得一個設(shè)備描述表,用畢,用::ReleaseDC或::EndPaint釋放設(shè)備描述表;
Printer設(shè)備描述表通過::CreateDC創(chuàng)建設(shè)備描述表,用::DeleteDC刪除設(shè)備描述表。
Memory設(shè)備描述表通過::CreateCompatibleDC創(chuàng)建設(shè)備描述表,用::DeleteDC刪除。
Information設(shè)備描述表通過::CreateIC創(chuàng)建設(shè)備描述表,用::DeleteDC刪除。
(2)改變設(shè)備描述表屬性的途徑
要改變設(shè)備描述表的屬性,可通過以下途徑:
用::SelectObject選入新的除調(diào)色板以外的GDI Object到設(shè)備描述表中;
對于調(diào)色板,使用::SelectPalette函數(shù)選入邏輯調(diào)色板,并使用::RealizePalette把邏輯調(diào)色板的入口映射到物理調(diào)色板中。
用其他API函數(shù)改變其他屬性,如::SetMapMode改變映射模式。
?
?
?
?
MFC提供了CDC類作為設(shè)備描述表類的基類,它封裝了Windows的HDC設(shè)備描述表對象和相關(guān)函數(shù)。
?
?
CDC類包含了各種類型的Windows設(shè)備描述表的全部功能,封裝了所有的Win32 GDI 函數(shù)和設(shè)備描述表相關(guān)的SDK函數(shù)。在MFC下,使用CDC的成員函數(shù)來完成所有的窗口繪制工作。
CDC 類的結(jié)構(gòu)示意圖2-2所示。
?
CDC類有兩個成員變量:m_hDC,m_hAttribDC,它們都是Windows設(shè)備描述表句柄。CDC的成員函數(shù)作輸出操作時,使用m_Hdc;要獲取設(shè)備描述表的屬性時,使用m_hAttribDC。
在創(chuàng)建一個CDC類實例時,缺省的m_hDC等于m_hAttribDC。如果需要的話,程序員可以分別指定它們。例如,MFC框架實現(xiàn)CMetaFileDC類時,就是如此:CMetaFileDC從物理設(shè)備上讀取設(shè)備信息,輸出則送到元文件(metafile)上,所以m_hDC和m_hAttribDC是不同的,各司其責(zé)。還有一個類似的例子:打印預(yù)覽的實現(xiàn),一個代表打印機(jī)模擬輸出,一個代表屏幕顯示。
CDC封裝::SelectObject(HDC hdc,HGDIOBJECT hgdiobject)函數(shù)時,采用了重載技術(shù),即它針對不同的GDI對象,提供了名同而參數(shù)不同的成員函數(shù):
SelectObject(CPen *pen)用于選入筆;
SelectObject(CBitmap* pBitmap)用于選入位圖;
SelectObject(CRgn *pRgn)用于選入剪裁區(qū)域;
SelectObject(CBrush *pBrush)用于選入刷子;
SelectObject(CFont *pFont)用于選入字體;
至于調(diào)色板,使用SelectPalette(CPalette *pPalette,BOOL bForceBackground )選入調(diào)色板到設(shè)備描述表,使用RealizePalletter()實現(xiàn)邏輯調(diào)色板到物理調(diào)色板的映射。
?
?
?
?
從CDC 派生出四個功能更具體的設(shè)備描述表類。層次如圖2-3所示。
?
?
下面,分別討論派生出的四種設(shè)備描述表。
?
- CCientDC
?
?
?
代表窗口客戶區(qū)的設(shè)備描述表。其構(gòu)造函數(shù)CClientDC(CWnd *pWin)通過::GetDC獲取指定窗口的客戶區(qū)的設(shè)備描述表HDC,并且使用成員函數(shù)Attach把它和CClientDC對象捆綁在一起;其析構(gòu)函數(shù)使用成員函數(shù)Detach把設(shè)備描述表句柄HDC分離出來,并調(diào)用::ReleaseDC釋放設(shè)備描述表HDC。
?
- CPaintDC
?
?
?
僅僅用于響應(yīng)WM_PAINT消息時繪制窗口,因為它的構(gòu)造函數(shù)調(diào)用了::BeginPaint獲取設(shè)備描述表HDC,并且使用成員函數(shù)Attach把它和CPaintDC對象捆綁在一起;析構(gòu)函數(shù)使用成員函數(shù)Detach把設(shè)備描述表句柄HDC分離出來,并調(diào)用::EndPaint釋放設(shè)備描述表HDC,而::BeginPaint和::EndPaint僅僅在響應(yīng)WM_PAINT時使用。
?
- CMetaFileDC
?
?
?
用于生成元文件。
?
- CWindowDC
?
?
?
代表整個窗口區(qū)(包括非客戶區(qū))的設(shè)備描述表。其構(gòu)造函數(shù)CWindowDC(CWnd *pWin)通過::GetWindowDC獲取指定窗口的客戶區(qū)的設(shè)備描述表HDC,并使用Attach把它和CWindowDC對象捆綁在一起;其析構(gòu)函數(shù)使用Detach把設(shè)備描述表HDC分離出來,調(diào)用::ReleaseDC釋放設(shè)備描述表HDC。
?
?
?
?
?
?
首先,定義一個這些類的實例變量,通常在棧中定義。然后,使用它。
例如,MFC中CView對WM_PAINT消息的實現(xiàn)方法如下:
void CView::OnPaint()
{
// standard paint routine
CPaintDC dc(this);
OnPrepareDC(&dc);
OnDraw(&dc);
}
在棧中定義了CPaintDC類型的變量dc,隨著構(gòu)造函數(shù)的調(diào)用獲取了設(shè)備描述表;設(shè)備描述表使用完畢,超出其有效范圍就被自動地清除,隨著析構(gòu)函數(shù)的調(diào)用,其獲取的設(shè)備描述表被釋放。
如果希望在堆中創(chuàng)建,例如
CPaintDC *pDC;
pDC = new CPaintDC(this)
則在使用完畢時,用delete刪除pDC:
delete pDC;
?
?
?
?
?
需要注意的是:在生成CDC對象的時候,并不像它的派生類那樣,在構(gòu)造函數(shù)里獲取相應(yīng)的Windows設(shè)備描述表。最好不要使用::GetDC等函數(shù)來獲取一個設(shè)備描述表,而是創(chuàng)建一個設(shè)備描述表。其構(gòu)造函數(shù)如下:
CDC::CDC()
{
m_hDC = NULL;
m_hAttribDC = NULL;
m_bPrinting = FALSE;
}
其析構(gòu)函數(shù)如下:
CDC::~CDC()
{
if (m_hDC != NULL)
::DeleteDC(Detach());
}
在CDC析構(gòu)函數(shù)中,如果設(shè)備描述表句柄不空,則調(diào)用DeleteDC刪除它。這是直接使用CDC時最好創(chuàng)建Windows設(shè)備描述表的理由。如果設(shè)備描述表不是創(chuàng)建的,則應(yīng)該在析構(gòu)函數(shù)被調(diào)用前分離出設(shè)備描述表句柄并用::RealeaseDC釋放它,釋放后m_hDC為空,則在析構(gòu)函數(shù)調(diào)用時不會執(zhí)行::DeleteDC。當(dāng)然,不用擔(dān)心CDC的派生類的析構(gòu)函數(shù)調(diào)用CDC的析構(gòu)函數(shù),因為CDC::~CDC()不是虛擬析構(gòu)函數(shù)。
直接使用CDC的例子是內(nèi)存設(shè)備上下文,例如:
CDC dcMem; //聲明一個CDC對象
dcMem.CreateCompatibleDC(&dc); //創(chuàng)建設(shè)備描述表
pbmOld = dcMem.SelectObject(&m_bmBall);//更改設(shè)備描述表屬性
…//作一些繪制操作
?
dcMem.SelectObject(pbmOld);//恢復(fù)設(shè)備描述表的屬性
dcMem.DeleteDC(); //可以不調(diào)用,而讓析構(gòu)函數(shù)去刪除設(shè)備描述表
?
?
?
?
在討論設(shè)備描述表時,已經(jīng)多次涉及到GDI對象。這里,需強(qiáng)調(diào)一下:GDI對象要選入Windows 設(shè)備描述表后才能使用;用畢,要恢復(fù)設(shè)備描述表的原GDI對象,并刪除該GDI對象。
一般按如下步驟使用GDI對象:
Create or get a GDI OBJECT hNewGdi;
?
hOldGdi = ::SelectObject(hdc, hNewGdi)
……
::SelectObject(hdc, hOldGdi)
::DeleteObject(hNewGdi)
先創(chuàng)建或得到一個GDI對象,然后把它選入設(shè)備描述表并保存它原來的GDI對象;用畢恢復(fù)設(shè)備描述表原來的GDI對象并刪除新創(chuàng)建的GDI對象。
需要指出的是,如果hNewGdi是一個Stock GDI對象,可以不刪除(刪除也可以)。通過
HGDIOBJ GetStockObject(
int fnObject // type of stock object
);
來獲取Stock GDI對象。
?
?
?
MFC用一些類封裝了Windows GDI對象和相關(guān)函數(shù),層次結(jié)構(gòu)如圖2-4所示:
?
?
CGdiObject封裝了Windows GDI Object共有的特性。其派生類在繼承的基礎(chǔ)上,主要封裝了各類GDI的創(chuàng)建函數(shù)以及和具體GDI對象相關(guān)的操作。
?
CGdiObject的構(gòu)造函數(shù)僅僅讓m_hObject為空。如果m_hObject不空,其析構(gòu)函數(shù)將刪除對應(yīng)的Windows GDI對象。MFC GDI對象和Windows GDI對象的關(guān)系如圖2-5所示。
?
?
?
?
首先創(chuàng)建GDI對象,可分一步或兩步創(chuàng)建。一步創(chuàng)建就是構(gòu)造MFC對象和Windows GDI對象一步完成;兩步創(chuàng)建則先構(gòu)造MFC對象,接著創(chuàng)建Windows GDI對象。然后,把新創(chuàng)建的GDI對象選進(jìn)設(shè)備描述表,取代原GDI對象并保存。最后,恢復(fù)原GDI對象。例如:
void CMyView::OnDraw(CDC *pDC)
{
CPen penBlack; //構(gòu)造MFC CPen對象
if (penBlack.CreatePen(PS_SOLID, RGB(0, 0, 0)))
{
CPen *pOldPen = pDC->SelectObject(&penBlack)); //選進(jìn)設(shè)備表,保存原筆
…
pDC->SelectObject(pOldPen); //恢復(fù)原筆
}else
{
…
}
}
和在SDK下有一點不同的是:這里沒有DeleteObject。因為執(zhí)行完OnDraw后,棧中的penBlack被銷毀,它的析構(gòu)函數(shù)被調(diào)用,導(dǎo)致DeleteObject的調(diào)用。
還有一點要說明:
pDC->SelectObject(&penBlack)返回了一個CPen *指針,也就是說,它根據(jù)原來PEN的句柄創(chuàng)建了一個MFC CPen對象。這個對象是否需要刪除呢?不必要,因為它是一個臨時對象,MFC框架會自動地刪除它。當(dāng)然,在本函數(shù)執(zhí)行完畢把控制權(quán)返回給主消息循環(huán)之前,該對象是有效的。
轉(zhuǎn)載于:https://www.cnblogs.com/ghw0501/archive/2012/02/24/4733925.html
創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎勵來咯,堅持創(chuàng)作打卡瓜分現(xiàn)金大獎總結(jié)
以上是生活随笔為你收集整理的MFC和Win32之三___CGdiObject类和windows Gdi对象的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux的FHS(文件系统结构标准)剖
- 下一篇: 自已做的第一个autoconf程序(不断