赞
踩
OBJ_PAL
OBJ_FONT
OBJ_BITMAP // Returns the current selected bitmap.
也可分别调用CDC类的下列成员函数来做同样的事:
CPen* GetCurrentPen( ) const;
CBrush* GetCurrentBrush( ) const;
CFont* GetCurrentFont( ) const;
CBitmap* GetCurrentBitmap( ) const;
CPalette* GetCurrentPalette( ) const;
如:
HPEN hPen = (HPEN)GetCurrentObject(pDC->m_hDC, OBJ_PEN);
CPen* pPen = CPen::FromHandle(hPen);
等价于:
CPen* pPen = pDC-> GetCurrentPen( );
4 画图
在Windows中,绘图一般在视图窗口的客户区进行,使用的是设备上下文类CDC中各种绘图函数。
1. 映射模式与坐标系
1)默认映射模式
映射模式(map mode)影响所有的图形和文本绘制函数,它定义(将逻辑单位转换为设备单位所使用的)度量单位和坐标方向,Windows总是用逻辑单位来绘图。
缺省情况下,绘图的默认映射模式为MM_TEXT,其绘图单位为像素(只要不打印输出,屏幕绘图使用该模式就够了)。若窗口客户区的宽和高分别为w和h像素,则其x坐标是从左到右,范围为0 ~ w-1;y坐标是从上到下,范围为0 ~ h-1。
2)设置映射模式
可以使用CDC类的成员函数GetMapMode和SetMapMode来获得和设置当前的映射模式:
int GetMapMode( ) const; // 返回当前的映射模式
virtual int SetMapMode( int nMapMode ); // 返回先前的映射模式
映射模式的nMapMode取值与含义
符号常量 数字常量 x方向 y方向 逻辑单位的大小
MM_TEXT 1 向右 向下 像素
MM_LOMETRIC 2 向右 向上 0.1 mm
MM_HIMETRIC 3 向右 向上 0.01 mm
MM_LOENGLISH 4 向右 向上 0.01 in
MM_HIENGLISH 5 向右 向上 0.001 in
MM_TWIPS 6 向右 向上 1/1440 in
MM_ISOTROPIC 7 自定义 自定义 自定义
MM_ANISOTROPIC 8 自定义 自定义 自定义
可见,除了两种自定义映射模式外,x方向都是向右,y方向也只有MM_TEXT的向下,其余的都是向上,与数学上一致。除了MM_ANISOTROPIC外,其他所有映射模式的x与y方向的单位都是相同的。所有映射模式的逻辑坐标的原点(0, 0)最初都是在窗口的左上角,但在CScrollView的派生类中,MFC会随用户滚动文档而自动调整逻辑原点的相对位置(改变视点的原点属性)。
3)自定义映射模式
自定义映射模式MM_ISOTROPIC(各向同性,x与y方向的单位必须相同)和MM_ANISOTROPIC(各向异性,x与y方向的单位可以不同)的单位和方向,可以通过用CDC类的成员函数G/SetWindowExt和G/SetViewportExt来获取/设置窗口和视口的大小来确定:
CSize GetWindowExt( ) const;
virtual CSize SetWindowExt( int cx, int cy );
virtual CSize SetWindowExt( SIZE size );
CSize GetViewportExt( ) const;
virtual CSize SetViewportExt( int cx, int cy );
virtual CSize SetViewportExt( SIZE size );
其中,cx或size.cx和cy或size.cy分别为窗口/视口的宽度与高度(逻辑单位)。
还可以用CDC类的成员函数SetViewportOrg来设置坐标原点的位置:
virtual CPoint SetViewportOrg( int x, int y );
CPoint SetViewportOrg( POINT point );
例如
void CDrawView::OnDraw(CDC* pDC) {
}
将当前的映射模式设置为各向异性自定义映射模式,窗口大小为1000个逻辑单位宽和1000个逻辑单位高,视口大小同当前客户区,视口的坐标原点设置在当前客户区的中央。由于使用了负数作为SetViewportExt函数的第2个参数,所以y轴方向是向上的。
可见,圆被画成了椭圆,x与y方向上的逻辑单位不相同。
4)单位转换
对所有非MM_TEXT映射模式,有如下重要规则:
CDC的成员函数(如各种绘图函数)具有逻辑坐标参数
CWnd的成员函数(如各种响应函数)具有设备坐标参数(如鼠标位置point)
位置的测试操作(如CRect的PtInRect函数)只有使用设备坐标时才有效
长期使用的值应该用逻辑坐标保存(如窗口滚动后保存的设备坐标就无效了)
因此,为了使应用程序能够正确工作,除MM_TEXT映射模式外,其他映射模式都需要进行单位转换。下面是逻辑单位到设备单位(如像素)的转换公式:
x比例因子 = 视口宽度 / 窗口宽度
y比例因子 = 视口高度 / 窗口高度
设备x = 逻辑x * x比例因子 + x原点偏移量
设备y = 逻辑y * y比例因子 + y原点偏移量
Windows的GDI负责逻辑坐标和设备坐标之间的转换,这可以调用CDC类的成员函数LPtoDP和DPtoLP来进行:
void LPtoDP( LPPOINT lpPoints, int nCount = 1 ) const;
void LPtoDP( LPRECT lpRect ) const;
void LPtoDP( LPSIZE lpSize ) const;
void DPtoLP( LPPOINT lpPoints, int nCount = 1 ) const;
void DPtoLP( LPRECT lpRect ) const;
void DPtoLP( LPSIZE lpSize ) const;
例如:
void CDrawView::OnLButtonDown(UINT nFlags, CPoint point) {
}
void CDrawView:: OnMouseMove (UINT nFlags, CPoint point) {
pDC->SetMapMode(MM_HIMETRIC);
t = t1 + (point.x * dt) / w; sprintf(buf, "%.4fs", t); pSB->SetPaneText(xV, buf);
y = (y0 - point.y) / dy; sprintf(buf, "%.4f", y); pSB->SetPaneText(yV, buf);
}
2. 画像素点
画像素点就是设置像素点的颜色,从前面3)(2)已知道这可由CDC的成员函数SetPixel来做,该函数的原型为:
COLORREF SetPixel( int x, int y, COLORREF crColor ); 或
COLORREF SetPixel( POINT point, COLORREF crColor );
其中,x与y分别为像素点的横坐标与纵坐标,crColor为像素的颜色值。例如
pDC->SetPixel(i, j, RGB(r, g, b));
3.画线状图
在Windows中,线状图必须用笔来画(笔的创建与使用见前面的3)(3)),下面是CDC类中可以绘制线状图的常用成员函数:
当前位置:设置当前位置为(x, y)或point:(返回值为原当前位置的坐标)
CPoint MoveTo( int x, int y ); 或 CPoint MoveTo( POINT point );
画线:使用DC中的笔从当前位置画线到点(x, y)或point:(若成功返回非0值):
BOOL LineTo( int x, int y ); 或BOOL LineTo( POINT point );
画折线:使用DC中的笔,依次将点数组lpPoints中的nCount(≥2)个点连接起来,形成一条折线:
BOOL Polyline( LPPOINT lpPoints, int nCount );
画多边形:似画折线,但还会将最后的点与第一个点相连形成多边形,并用DC中的刷填充其内部区域:
BOOL Polygon( LPPOINT lpPoints, int nCount );
画矩形:使用DC中的笔画左上角为(x1, y1)、右下角为(x2, y2)或范围为*lpRect的矩形的边线,并用DC中的刷填充其内部区域:
BOOL Rectangle( int x1, int y1, int x2, int y2 ); 或
BOOL Rectangle( LPCRECT lpRect );
画圆角矩形:使用DC中的笔画左上角为(x1, y1)、右下角为(x2, y2)或范围为*lpRect的矩形的边线,并用宽x3或point.x高y3或point.y矩形的内接椭圆倒角,再用DC中的刷填充其内部区域:
BOOL RoundRect( int x1, int y1, int x2, int y2, int x3, int y3 );
BOOL RoundRect( LPCRECT lpRect, POINT point );
例如:
int d = min(rect.Width(), rect.Height()) / 4;
pDC-> RoundRect(rect, CPoint(d, d));
画(椭)圆:使用DC中的笔在左上角为(x1, y1)、右下角为(x2, y2)或范围为*lpRect的矩形中画内接(椭)圆的边线,并用DC中的刷填充其内部区域:
BOOL Ellipse( int x1, int y1, int x2, int y2 );
BOOL Ellipse( LPCRECT lpRect );
注意,CDC中没有画圆的专用函数。在这里,圆是作为椭圆的(宽高相等)特例来画的。
画弧:(x1, y1)与(x2, y2)或lpRect的含义同画(椭)圆,(x3, y3)或ptStart为弧的起点,(x4, y4)或ptEnd为弧的终点:(逆时针方向旋转)
BOOL Arc( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );
BOOL Arc( LPCRECT lpRect, POINT ptStart, POINT ptEnd );
BOOL ArcTo(int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4);
BOOL ArcTo(LPCRECT lpRect, POINT ptStart, POINT ptEnd);
画圆弧:(其中(x, y)为圆心、nRadius为半径、fStartAngle为起始角、fSweepAngle为弧段跨角)
BOOL AngleArc(int x, int y, int nRadius, float fStartAngle, float fSweepAngle);
画弓弦:参数的含义同上,只是用一根弦连接弧的起点和终点,形成一个弓形,并用DC中的刷填充其内部区域:
BOOL Chord( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );
BOOL Chord( LPCRECT lpRect, POINT ptStart, POINT ptEnd );
4.画填充图
在Windows中,面状图必须用刷来填充(刷的创建与使用见前面的3)(4))。上面(2)中的Polygon、Rectangle、Ellipse和Chord等画闭合线状图的函数,只要DC中的刷不是空刷,都可以用来画对应的面状图(边线用当前笔画,内部用当前刷填充)。下面介绍的是CDC类中只能绘制面状图的其他常用成员函数:
画填充矩形:用指定的刷pBrush画一个以lpRect为区域的填充矩形,无边线,填充区域包括矩形的左边界和上边界,但不包括矩形的右边界和下边界:
void FillRect( LPCRECT lpRect, CBrush* pBrush );
画单色填充矩形:似FillRect,但只能填充单色,不能填充条纹和图案:
void FillSolidRect( LPCRECT lpRect, COLORREF clr );
void FillSolidRect( int x, int y, int cx, int cy, COLORREF clr );
画饼图(扇形):参数含义同Arc,但将起点和终点都与外接矩形的中心相连接,形成一个扇形区域,用DC中的刷填充整个扇形区域,无另外的边线:
BOOL Pie( int x1, int y1, int x2, int y2, int x3, int y3, int x4, int y4 );
BOOL Pie( LPCRECT lpRect, POINT ptStart, POINT ptEnd );
画拖动的矩形:先擦除线宽为sizeLast、填充刷为pBrushLast的原矩形lpRectLast,然后再以线宽为size、填充刷为pBrush画新矩形lpRectLast。矩形的边框用灰色的点虚线画,缺省的填充刷为空刷:
void DrawDragRect( LPCRECT lpRect, SIZE size, LPCRECT lpRectLast,
SIZE sizeLast, CBrush* pBrush = NULL, CBrush* pBrushLast = NULL );
如:pDC->DrawDragRect(rect, size, rect0, size);
填充区域:
用当前刷从点(x, y)开始向四周填充到颜色为crColor的边界:
BOOL FloodFill(int x, int y, COLORREF crColor); // 成功返回非0
用当前刷从点(x, y)开始向四周填充:
BOOL ExtFloodFill(int x, int y, COLORREF crColor,
UINT nFillType); // 成功返回非0
nFillType = FLOODFILLBORDER:填充到颜色为crColor的边界(同FloodFill);(用于填充内部颜色不同但边界颜色相同的区域)
nFillType = FLOODFILLSURFACE:填充所有颜色为crColor的点,直到碰到非crColor颜色的点为止。(点(x, y)的颜色也必须为crColor),(用于填充内部颜色相同但边界颜色可以不同的区域)。例如:
pDC->ExtFloodFill(point.x, point.y, pDC->GetPixel(point), FLOODFILLSURFACE);
5.清屏
Windows没有提供专门的清屏函数,可以调用CWnd的下面两个函数调用来完成该功能:
void Invalidate(BOOL bErase = TRUE);
void UpdateWindow( );
或调用CWnd的函数
BOOL RedrawWindow(
);
来完成。
例如(菜单项ID_CLEAR的事件处理函数):
CDrawView::OnClear() { // 调用OnDraw来清屏
}
也可以用画填充背景色矩形的方法来清屏,如:
6.在控件上绘图
可以在对话框资源中放置图片控件,并对其类型属性选Frame。可在对话框的绘图消息响应函数OnPaint或其他函数中,用CWnd类的函数GetDlgItem:
CWnd* GetDlgItem( int nID ) const;
来获得图片控件的窗口对象,再用函数GetDC:
CDC* GetDC( );
由窗口对象得到DC,然后就可以用该DC在控件中画图。如(在ID为IDC_HUESAT的图片控件上画调色板)
void CColorDlg::OnPaint()
{