/**********************************************/
第五章:图形设备接口(GDI)、颜色及字体
1,任何时候当程序需要直接在屏幕或打印机上绘图的时候,都需要调用GDI函数,GDI函数包含了一些用于绘制图形、位图以及文本的函数。
2,Windows的设备环境是GDI的关键元素,它代表了物理设备。每一个C++设备环境对象都有与之对应的Windows设备环境,并且通过一个32位类型的HDC句柄来标识。
3,MFC库设备环境类基类CDC包含了绘图所需要的所有成员函数,并且几乎所有派生类只有构造函数和析构函数不同(CMetaFileDC类除外)。
对于显示器来说,常用的派生类有CClientDC 和 CWindowDC,而对其它设备(如打印机或内存缓冲区),则可以构造一个基类CDC的对象。
对于显示器和打印机设备环境对象来说,应用程序框架会直接将句柄附在对象上;而对其它设备环境(如内存设备环境),为了将对象与句柄相联系,在构造完对象之后,还必须调用一个成员函数(进行初试化)。
4,CClientDC类 和 CWindowDC类
CClientDC( CWnd* pWnd );
//Constructs a CClientDC object that accesses the client area of the CWnd pointed to by pWnd. The constructor calls the Windows function GetDC.
CWindowDC( CWnd* pWnd );
//Constructs a CWindowDC object that accesses the entire screen area (both client and nonclient) of the CWnd object pointed to by pWnd. The constructor calls the Windows function GetWindowDC.
如果构造CClientDC对象,则设备环境的映射区域限于客户区域,不能在客户区域外绘图。原点(0,0)在客户区左上角。
《 如果创建CWindowDC对象,则设备环境的映射区域为整个窗口(包括标题栏、状态栏、窗口边框等)。原点(0,0)在整个窗口的左上角。》
注意:
1)视图窗口没有非客户区域.
2)视图窗口覆盖在框架窗口之上。
3)在《》中的内容,是我根据测试所理解的。翻译原文中映射区域是整个显示屏幕,原点(0,0)在整个屏幕的左上角。这显然是不对的。
5,在创建了一个CDC对象后,一定要注意在完成任务后将其删除。(如果用CClientDC 或 CWindowDC来在堆栈中构造一个DC对象,则不需要我们显式的删除它,CClientDC或CWindowDC对象会在它的生命周期结束的时候自动调用析构函数来完成删除工作)
例如:
CDC *pDC=GetDC();
...
RealeaseDC(pDC);
说明:
CDC* GetDC( );//CWnd::GetDC 获得与当前窗口相关联的CDC对象指针(映射窗口客户区域)
int ReleaseDC( CDC* pDC );//CWnd::ReleaseDC 释放与当前窗口相关联的设备环境
注意:
在MFC程序中,千万不能自己添加代码删除作为参数以指针形式传递给OnDraw(CDC* pDC)函数的CDC对象,应用程序会自动控制它的删除。
6,当利用CDC对象绘图的时候,所绘制的图形都要依赖于设备环境的状态:如画笔、画刷、字体等GDI绘图对象 和 当前映射模式的选择等。
可以使用CDC成员函数了设置所需要的饿设备环境状态。如:SelectObject()函数可将GDI对象随时选入设备环境中。
7,CPaintDC类:当需要重写OnPaint函数的时候,就需要使用CPaintDC类。默认的OnPaint函数会使用已经设置好的设备环境来调用OnDraw函数
注意:CPaintDC类的构造函数和析构函数所完成的工作都是针对显示用的。
例:
void CMyView::OnPaint()
{
CPaintDC dc(this);
OnPrepareDC(&dc);
dc.TextOut(0,0,"for the display,not the printer");
OnDraw(&dc);
}
说明:
1)CPaintDC( CWnd* pWnd );
//CPaintDC::CPaintDC Constructs a CPaintDC object, prepares the application window for painting, and stores the PAINTSTRUCT structure in the m_ps member variable.
2)CPaintDC类的构造函数自动调用BeginPaint,而它的析构函数会自动调用EndPaint.
3)CDC* BeginPaint( LPPAINTSTRUCT lpPaint );
//CWnd::BeginPaint Prepares CWnd for painting and fills a PAINTSTRUCT data structure with information about the painting.
void EndPaint( LPPAINTSTRUCT lpPaint );
//CWnd::EndPaint Marks the end of painting in the given window. The EndPaint member function is required for each call to the BeginPaint member function, but only after painting is complete.
问题:
1)在View类中一旦定义了OnPaint()函数,则WM_PAINT消息由OnPaint函数来响应。OnDraw函数不再被调用。原因?
8,GDI对象:
Class Windows handle type
CPen HPEN
CBrush HBRUSH
CFont HFONT
CBitmap HBITMAP
CPalette HPALETTE
CRgn HRGN
说明:
Each graphic-object class in the class library has a constructor that allows you to create graphic objects of that class, which you must then initialize with the appropriate create function, such as CreatePen.
Each graphic-object class in the class library has a cast operator that will cast an MFC object to the associated Windows handle. The resulting handle is valid until the associated object detaches it. Use the object’s Detach member function to detach the handle.
9,CGdiObject类有一个虚析构函数,在其派生类的析构函数将与C++对象相关联的WINDOWS GDI对象删除掉。如果构造了一个CGdiObject派生类对象,则在退出程序之前,必须将其删除掉。
利用CDC类的SelectObject成员函数把自己的GDI对象选进DC的同时,保存原来的GDI对象,当任务完成后,恢复原来的GDI对象,这样就可以将自己的GDI对象的删除掉。
如:
GDIStyle *poldGdiObject=pDC->SelectObject(&newGdiObject);
...//完成任务
pDC->SelectObject(poldGdiObject);
10,Windows对任何企图删除库存GDI对象的行为都不予理会。可以利用SelectObject函数把库存GDI对象选入,从而删除当前GDI对象。
原因:
This function SelectObject may return a pointer to a temporary object. This temporary object is only valid during the processing of one Windows message.
如:
pDC->SelectObject(&newGdiObject);
...
pDC->SelectStockObject(StockCGdiObject);//如:BLACK_BRUSH
11,对于显示设备环境,在消息处理函数内部所进行GDI选择在函数退出后不再有效,因此在进入其他处理函数的时候,每次都必须重新设置设备环境。
Windows句柄是唯一能够持久存在的GDI标识。可以使用GDI对象指针调用GetSafeHandle函数可以获得它Windows句柄,再利用GDI对象类的FromHandle函数将句柄转化为对应的GDI对象。
如:
CFont *pOldFont=pDC->SelectObject(&newFont);
m_hOldFont=(HFONT)pOldFont->GetSafeHandle();//m_hOldFont为数据成员,保存先前字体对象句柄
...
pDC->SelectObject(CFont::FromHandle(m_hOldFont));//可在其他函数中,恢复m_hOldFont句柄对应的字体对象。
说明:
1)static CFont* PASCAL FromHandle( HFONT hFont );
//CFont::FromHandle Returns a pointer to a CFont object when given an HFONT handle to a Windows GDI font object. If a CFont object is not already attached to the handle, a temporary CFont object is created and attached.
2)CGdiObject::GetSafeHandle();
//Return A HANDLE to the attached Windows GDI object; otherwise NULL if no object is attached.
12,每一种Windows颜色都是 通过8位的红(R)、绿(G)、蓝(B)的值祝贺来表示的。
面向颜色的GDI函数可以接收32位的COLORREF参数。Windows的RGB宏可以将8位的红绿蓝值转化成COLORREF参数。
说明:
1)The COLORREF value is a 32-bit value used to specify an RGB color.
2)16种标准VGA纯色参见 P70页;256显示卡 多增加4种标准色参见 P71页。
13,字体是GDI对象,在使用上和其它的GDI对象完全一样。
CDC::GetTextMetrics
BOOL GetTextMetrics( LPTEXTMETRIC lpMetrics ) const;//测量字体高度等参数
14,GetDeviceCaps();
//Retrieves a wide range of device-specific information about the display device.