设备上下文 :m_hDC 或者GetSafeHdc函数
CDC对象: CDC对象或指针 或FromHandle
关联:Attach
分离:Detach
一、客户区大小和DC
在绘图前,必须先得到客户区大小和设备上下文DC。
客户区大小(2种办法)
1)在消息响应函数OnSize中获得
利用属性窗口的信息页,在视图类中添加WM_SIZE消息的响应函数OnSize。该函数在窗口第一次显示或窗口大小被改变时会被Windows系统调用。其输入参数中的cx和cy就是客户区大小的宽和高。
void CDrawView::OnSize(UINT nType, int cx, int cy) {
CView::OnSize(nType, cx, cy);
// TODO: 在此处添加消息处理程序代码
m_iW = cx; m_iH = cy;
}
2. void GetClientRect( LPRECT lpRect ) const;
得到当前客户区矩形的数据,其中的右(right)与底(bottom)就是客户区的宽与高(其左left与顶top都为0)
获得DC
可以从OnDraw函数的输入参数pDC或调用CWnd的成员函数GetDC:
1)CDC* GetDC( );
来获得DC的指针。
2) 释放DC
因为Windows限制可用DC的数量,所以DC属于稀缺的公用资源。因此,对每次获得的DC,在使用完成后必须立即释放。
从OnDraw函数的输入参数pDC获得的DC,在该函数运行结束后,系统会自动释放。但由GetDC所获得的DC,必须自己来释放,这可以通过调用CWnd的成员函数ReleaseDC来完成:
int ReleaseDC( CDC* pDC ); // 成功返回非0
二、GDI对象
Windows的图形设备接口(GDI = graphics device interface)对象指各种绘图工具,如笔、刷、位图、字体、调色板、区域等,对应的MFC类为CPen、CBrush、CBitmap、CFont等。这些图形绘制对象类都是CGDIObject的派生类,而CGDIObject则是直接从CObject类派生的抽象基类。
创建这些对象有两种方法:一种是调用构造函数,另一种是调用相关的成员函数。
CPen(int nPenStyle, int nWidth, COLORREF crColor);
BOOL CreatePen(int nPenStyle, int nWidth, COLORREF crColor);
pen1.CreatePen(PS_SOLID,1 ,RGB(192,192,192));//创建对象
nPenStyle可以是
PS_SOLID : 画笔画出的是实线。
PS_DASH: 画笔画出的是虚线(nWidth必须不大于1)。
PS_DOT: 画笔画出的是点线(nWidth必须不大于1)。
PS_DASHDOT:画笔画出的是点划线(nWidth必须不大于1)。
PS_DASHDOTDOT: 画笔画出的是点-点-划线(nWidth必须不大于1)。
PS_NULL: 空画笔,画笔不能画图。
CBrush(COLORREF crColor); // CreateSolidBrush
CBrush(int nIndex, COLORREF crColor); // CreateHatchBrush
BOOL CreateSolidBrush(COLORREF crColor);
BOOL CreateHatchBrush(int nIndex, COLORREF crColor);
crColor指定画刷的前景色(RGB方式)。如果画刷是阴影线型的,则指定阴影线的颜色。
nIndex指定画刷阴影线采用的风格,取值如下:
HS_BDIAGONAL45度的向下影线(从左到右)
HS_CROSS水平和垂直方向以网格线作出阴影
HS_DIAGCROSS 45度的网格线阴影
HS_FDIAGONAL 45度的向上阴影线(从左到右)
HS_HORIZONTAL 水平的阴影线
HS_VERTICAL 垂直的阴影线
CFont
BOOL CreateFontIndirect(const LOGFONT* lpLogFont);
BOOL CreateFont(int nHeight, int nWidth, int nEscapement,
int nOrientation, int nWeight, BYTE bItalic, BYTE bUnderline,
BYTE cStrikeOut, BYTE nCharSet, BYTE nOutPrecision,
BYTE nClipPrecision, BYTE nQuality, BYTE nPitchAndFamily,
LPCTSTR lpszFacename);
CFont font;
font.CreateFont(20, _T("宋体"));
CBitmap
BOOL LoadBitmap(LPCTSTR lpszResourceName);
CBitmap* SelectObject(CBitmap* pBitmap);
选入
可用设备上下文类CDC的多态成员函数SelectObject,来将绘图工具对象选入设备上下文,以供绘图时使用:
CPen* SelectObject( CPen* pPen );
CBrush* SelectObject( CBrush* pBrush );
virtual CFont* SelectObject( CFont* pFont );
CBitmap* SelectObject( CBitmap* pBitmap );
int SelectObject( CRgn* pRgn );
CGdiObject* SelectObject( CGdiObject* pObject );
获取
CPen* GetCurrentPen( ) const;
CBrush* GetCurrentBrush( ) const;
CFont* GetCurrentFont( ) const;
CBitmap* GetCurrentBitmap( ) const;
CPalette* GetCurrentPalette( ) const;
清屏
Windows没有提供专门的清屏函数,可以调用CWnd的下面两个函数调用来完成该功能:
void Invalidate(BOOL bErase = TRUE);
void UpdateWindow( );
为指定设备创建设备上下文 |
删除CDC对象对应的Windows设备上下文 |
给定设备上下文句柄时,返回指向CDC对象的指针。如果CDC对象未附加到句柄,则创建并附加一个临时CDC对象 |
返回输出设备上下文m_hDC |
创建内存设备上下文,与另一个设备上下文匹配。可以用它在内存中准备图像 |
映射和坐标
默认映射模式
映射模式(map mode)影响所有的图形和文本绘制函数,它定义(将逻辑单位转换为设备单位所使用的)度量单位和坐标方向,Windows总是用逻辑单位来绘图。
缺省情况下,绘图的默认映射模式为MM_TEXT,其绘图单位为像素(只要不打印输出,屏幕绘图使用该模式就够了)。
设置映射模式
可以使用CDC类的成员函数GetMapMode和SetMapMode来获得和设置当前的映射模式:
符号常量 | 数字常量 | x方向 | y方向 | 逻辑单位的大小 |
MM_TEXT | 1 | 向右 | 向下 | 像素 |
逻辑坐标(窗口坐标) | 物理坐标(设备坐标、视口坐标) |
可以像素、mm等单位 | 只能是像素 |
GetWindowOrg | GetViewportOrg |
GetWindowExt | GetViewportExt |
坐标:
设备单位转换为逻辑单位 | |
逻辑单位转换为设备单位 |
单位转换
对所有非MM_TEXT映射模式,有如下重要规则:
CDC的成员函数(如各种绘图函数)具有逻辑坐标参数
CWnd的成员函数(如各种响应函数)具有设备坐标参数(如鼠标位置point)
位置的测试操作(如CRect的PtInRect函数)只有使用设备坐标时才有效
长期使用的值应该用逻辑坐标保存(如窗口滚动后保存的设备坐标就无效了)
因此,为了使应用程序能够正确工作,除MM_TEXT映射模式外,其他映射模式都需要进行单位转换。下面是逻辑单位到设备单位(如像素)的转换公式:
x比例因子 = 视口宽度 / 窗口宽度
y比例因子 = 视口高度 / 窗口高度
设备x = 逻辑x * x比例因子 + x原点偏移量
设备y = 逻辑y * y比例因子 + y原点偏移量
Windows的GDI负责逻辑坐标和设备坐标之间的转换,这可以调用CDC类的成员函数LPtoDP和DPtoLP来进行:
绘图属性
获取当前背景色 | |
设置当前背景色 | |
获取背景模式 | |
设置背景模式 |
获取当前文本颜色 | |
设置文本颜色 |
SetBkMode函数来设置DrawText函数的输出方式,显示设备共有两种输出方式:OPAQUE和TRANSPARENT。
OPAQUE的方式是用当前背景的画刷的颜色输出显示文字的背景。
而TRANSPARENT是使用透明的输出,也就是文字的背景是不改变的。
如果是透明的,则背景颜色将不起作用,其颜色将和整个客户区的背景颜色相同,如果是不透明的,就需要自己指定的背景颜色;
绘图
用指定画刷填充给定矩形 |
移动当前位置 | |
从当前位置到一点画直线,但不包括那个点 |
绘制图标 |
用当前选取字体在指定位置写字符串 |
在指定矩形内绘制格式化文本 |
使用当前字体在属性设备上下文上计算文本行的宽度和高度,确定维数 |