简介:MFC是一个C++库,封装了Windows API,用于高效构建Windows应用程序。本主题将演示如何使用MFC框架中的CDC类绘制直线和三角形,并扩展到绘制其他图形。CDC类提供了基本的绘图方法,如MoveTo()、LineTo()、Polygon()等。代码示例展示了如何在CView派生类中实现OnDraw()方法进行基本绘图,并覆盖鼠标事件以实现交互式图形绘制。熟练掌握MFC中的CDC和GDI是构建Windows图形界面的关键。
1. MFC框架绘图简介
在深入探讨MFC框架中的绘图机制之前,让我们首先了解什么是MFC,以及它如何为Windows程序提供绘图环境。MFC,全称Microsoft Foundation Classes,是微软提供的一个用于简化Windows应用程序开发的C++类库。它封装了许多Windows API,使得开发者可以更容易地使用面向对象的方法进行GUI开发。
MFC框架的基础知识与绘图环境设置
基础知识
MFC框架将Windows程序的界面分解为多个元素,如窗口、按钮、文本框等,并提供了丰富的类来处理这些元素。绘图方面,MFC使用设备上下文(Device Context,DC)来描述窗口和图像的属性,为绘图操作提供了一个抽象层。
绘图环境设置
在MFC应用程序中,绘图环境的设置通常在视图类(CView的派生类)中通过覆盖 OnDraw()
方法来完成。 OnDraw()
方法在视图需要更新其内容时被调用,它接受一个设备上下文对象的引用,该对象是绘图操作的入口点。
void CYourView::OnDraw(CDC* pDC)
{
CDocument* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// 绘图代码将在这里编写
}
在这个方法中,你可以使用CDC类提供的方法来执行绘制操作,比如使用画笔绘制线条、使用画刷填充形状等。理解CDC类和GDI对象的使用是进行MFC绘图开发的基础。
本章向我们介绍了MFC框架绘图的基础知识,并概述了如何在MFC中设置绘图环境,为后续章节深入探讨CDC类和GDI对象的使用以及各种图形的绘制奠定了基础。接下来的章节会深入CDC类和GDI的具体操作,为进行复杂绘图任务打下坚实的基础。
2. CDC类和GDI基础
2.1 CDC类概述及其与设备上下文的关系
2.1.1 CDC类的功能和特性
在MFC(Microsoft Foundation Classes)框架中,CDC类是提供设备上下文访问的主要接口,它封装了Windows GDI(Graphics Device Interface)的大多数功能。CDC类的功能和特性使得它能够处理各种绘图任务,包括但不限于画线、绘图形状、处理图像和文本等。
CDC类支持直接与GDI对象交互,如画笔(CPen)、画刷(CBrush)、位图(CBitmap)等,为应用程序提供了丰富的绘图能力。通过CDC类,程序员能够获取当前设备的属性信息,进行图形绘制,并对绘图环境进行各种设置。
此外,CDC类在MFC中的层次结构为开发者提供了丰富的方法集合,便于对绘图操作进行封装和扩展。例如,CDC类继承自CObject,这为它提供了序列化和诊断功能。同时,它也提供了一系列的重载方法,使得绘图操作更加灵活和高效。
2.1.2 设备上下文的概念及其在绘图中的作用
设备上下文(Device Context,DC)是GDI中的一个核心概念,它是Windows图形编程中的一个抽象数据结构,用于定义一个设备的图形特性以及绘图时的环境。
设备上下文的作用如下:
- 定义了目标设备(比如屏幕、打印机)的图形特性,如分辨率、颜色位数等。
- 确定了绘图操作的坐标系统和映射模式,这些决定了图形对象如何在设备上呈现。
- 管理GDI对象,如画笔、画刷、字体等,并提供了一套方法来改变当前使用的GDI对象。
在MFC中,CDC类为开发者提供了操作设备上下文的接口。通过CDC对象,程序员可以轻松地获取和设置设备上下文的属性,完成从基本到复杂的绘图任务。例如,在CDC类中,可以使用 SetMapMode
函数设置映射模式,用 SelectObject
函数选择不同的GDI对象到设备上下文中去。
2.2 GDI对象的创建与管理
2.2.1 GDI对象的类型和创建方法
Windows GDI提供了一组丰富的对象用于绘图,包括画笔(Pen)、画刷(Brush)、字体(Font)、位图(Bitmap)、区域(Region)等。这些GDI对象可以通过CDC类的成员函数创建和管理。
- 画笔(CPen) :用于定义线条的样式、宽度和颜色。
- 画刷(CBrush) :用于定义填充图形或区域的样式和颜色。
- 字体(CFont) :用于定义文本的字体属性,如大小、风格、字体名称等。
- 位图(CBitmap) :用于创建和操作位图图像。
- 区域(CRgn) :用于定义一个屏幕区域,并可以用来裁剪绘图或进行碰撞检测。
创建GDI对象通常有如下两种方法:
- 使用MFC提供的相应类的构造函数创建对象,并调用
CreatePen
、CreateSolidBrush
等函数进行初始化。 - 直接调用GDI函数,如
CreatePen
、CreateSolidBrush
等,从底层API创建对象。
在创建对象后,通常将这些对象选入DC中进行绘制。完成绘制后,应调用 DeleteObject
释放资源,以避免内存泄漏。
2.2.2 GDI对象的选择和删除机制
当在MFC应用程序中使用GDI对象时,必须将它们选入CDC对象(即设备上下文)中。CDC类提供的 SelectObject
方法用于此目的。选择对象到设备上下文中实际上是将对象的句柄存入设备上下文中,使得后续的绘图操作使用该对象。
值得注意的是,当一个GDI对象被选入DC后,Windows会返回先前选入该DC的相应类型对象的句柄。这允许开发者在替换新的GDI对象后,仍可以恢复到旧的对象。当GDI对象不再需要时,开发者应调用 DeleteObject
来删除对象,并释放与之关联的系统资源。
例如,使用 CPen
创建一个画笔并将其选入DC中的代码片段如下:
CPen myPen(PS_SOLID, 1, RGB(0, 0, 0)); // 创建一个黑色的实线画笔
CPen* pOldPen = pDC->SelectObject(&myPen); // 选择画笔到DC中
// 在这里进行绘图操作...
pDC->SelectObject(pOldPen); // 恢复旧的画笔对象
delete pOldPen; // 释放旧的画笔对象
2.3 基本绘图工具的介绍
2.3.1 画笔、画刷、字体和位图
在MFC绘图中,画笔、画刷、字体和位图是基本的绘图工具,它们允许开发者在设备上下文中绘制各种图形和文本。
- 画笔 用于定义绘制线条的样式、宽度和颜色。通过创建
CPen
对象,可以创建不同类型的画笔,包括实线、虚线、点划线等。
CPen redPen(PS_SOLID, 2, RGB(255, 0, 0)); // 创建一个红色的实线画笔,宽度为2
- 画刷 用于定义填充图形的样式和颜色。通过创建
CBrush
对象,可以定义不同的画刷,包括纯色、图案、渐变等。
CBrush blueBrush(BS_SOLID, RGB(0, 0, 255)); // 创建一个蓝色的实心画刷
- 字体 用于绘制文本。通过创建
CFont
对象,可以设置文本的字体大小、风格等。
CFont myFont;
myFont.CreatePointFont(120, _T("Arial")); // 创建一个字体对象,大小为120
- 位图 用于显示图像。在MFC中,
CBitmap
类提供了操作位图的方法。通过它可以加载、创建和操作位图图像。
CBitmap myBitmap;
myBitmap.LoadBitmap(IDB_MYBITMAP); // 加载一个位图资源
2.3.2 GDI对象属性的设置和使用
在MFC中,通过创建GDI对象并设置其属性后,可以将它们选入到CDC对象中,以执行绘图操作。在此过程中,可以使用 SetBkMode
设置背景模式,使用 SetTextColor
设置文本颜色,使用 SetROP2
设置绘图模式等。
这里是一个基本的设置和使用GDI对象的示例:
CDC* pDC = GetDC(); // 获取设备上下文
CPen pen(PS_SOLID, 1, RGB(0, 255, 0)); // 创建一个绿色的实线画笔
CBrush brush(BS_SOLID, RGB(255, 255, 0)); // 创建一个黄色的实心画刷
pDC->SelectObject(&pen); // 选择画笔
pDC->SelectObject(&brush); // 选择画刷
pDC->Rectangle(10, 10, 200, 100); // 使用所选对象绘制矩形
pDC->SelectObject(pen); // 恢复原有的画笔
pDC->SelectObject(brush); // 恢复原有的画刷
ReleaseDC(pDC); // 释放设备上下文
在上述代码中,首先获取设备上下文 pDC
,然后创建画笔和画刷对象,并分别使用 SelectObject
方法将其选入到设备上下文中。在完成绘制后,恢复了原有的画笔和画刷对象,并释放了设备上下文资源。
CDC类和GDI对象是MFC绘图功能的基础,通过合理使用这些类和对象,开发者可以在Windows平台上构建出丰富的图形用户界面。
3. 绘制直线的CDC方法使用
3.1 使用MoveTo()和LineTo()绘制直线
3.1.1 移动到起点的MoveToEx()函数
在MFC(Microsoft Foundation Classes)框架中,绘制图形通常是从定义起点开始的。 MoveToEx()
函数是用来设置当前绘图位置到指定点的坐标,这是绘制线条之前必须执行的操作。当这个函数被调用时,它将设定一个起始点,之后使用 LineTo()
函数从这个点绘制到另一个点。
BOOL MoveToEx(
int x, // 新位置的 x 坐标
int y, // 新位置的 y 坐标
LPPOINT lpPoint // 可选,用于存储旧位置的 POINT 结构指针
);
-
x
和y
参数指定了新的绘图起始点坐标。 -
lpPoint
是一个指向POINT
结构的指针,用来保存之前的绘图位置。如果不需要保存旧位置,该参数可以设为NULL
。
在使用 MoveToEx()
设置起点之后,紧接着就可以使用 LineTo()
来绘制直线了。通常情况下,在连续绘制多条线段时, MoveToEx()
仅在第一次调用时使用,后续的线段绘制都通过 LineTo()
直接连接。
3.1.2 绘制直线的LineTo()函数
LineTo()
函数用于从当前绘图位置绘制一条直线到指定的点。它继承了上一次 MoveToEx()
的终点作为自己的起点,这使得连续绘制线段变得非常简单。
BOOL LineTo(
int x, // 直线终点的 x 坐标
int y // 直线终点的 y 坐标
);
-
x
和y
参数指定了直线终点的坐标。
绘制直线时, CDC
类会根据当前选择的画笔属性(例如颜色、宽度等)来渲染线条。如果绘制直线超出了视图的客户区,那么超出部分的直线不会被绘制。
3.2 理解坐标系统及其在直线绘制中的应用
3.2.1 客户区坐标与设备坐标
在MFC应用中,绘制图形时使用的坐标系统非常重要。主要有两种坐标系统:客户区坐标和设备坐标。
- 客户区坐标 :这是应用程序的视图部分内部使用的坐标系统。原点(0, 0)通常位于窗口的左上角,x坐标向右增加,y坐标向下增加。
- 设备坐标 :这是与设备相关的坐标系统,与物理显示设备的像素对应。设备坐标的原点(0, 0)在屏幕左上角,但也可根据不同的映射模式改变。
这两种坐标系统之间的转换是由设备上下文(DC)管理的,开发者在绘制图形时必须考虑这一点,以确保图形正确显示。
3.2.2 坐标转换与映射模式设置
为了能够正确地在屏幕上绘制对象,需要理解坐标转换的概念,并且正确设置映射模式。映射模式定义了逻辑单位和设备单位之间的转换关系。
映射模式主要有两种: MM_TEXT
和 MM_ANISOTROPIC
。 MM_TEXT
是默认的映射模式,它将一个逻辑单位映射到一个像素。而 MM_ANISOTROPIC
是自适应映射模式,它允许开发者定义不同的水平和垂直缩放比例,使得图形能够根据实际需要伸缩。
设置映射模式的函数为:
int SetMapMode(
int nMapMode // 映射模式
);
-
nMapMode
可以是MM_TEXT
,MM_LOENGLISH
等值,根据需要绘制图形的具体性质来选择。
例如,若需要自定义坐标单位,可以这样设置 MM_ANISOTROPIC
映射模式:
dc.SetMapMode(MM_ANISOTROPIC);
dc.SetWindowExt(800, 600); // 设置逻辑坐标范围
dc.SetViewportExt(800, 600); // 设置设备坐标范围
这里, SetWindowExt
定义了逻辑坐标的范围,而 SetViewportExt
定义了在视口上绘制图形时的视图范围。例如,设置逻辑坐标和视口坐标范围都是 800x600,意味着一个逻辑单位对应一个设备单位。
通过设置适当的映射模式,可以使得图形在不同分辨率或不同大小的窗口中正确地绘制和显示。这对于创建可伸缩用户界面和适应不同屏幕尺寸的图形应用非常重要。
3.3 实际绘制直线操作
让我们通过一个例子来展示如何使用这些方法绘制直线:
void CYourView::OnDraw(CDC* pDC)
{
CPen pen(PS_SOLID, 2, RGB(0, 0, 0)); // 创建一个黑色画笔,宽度为2
CBrush brush(RGB(255, 255, 0)); // 创建一个黄色的画刷
// 选择画笔和画刷到设备上下文中
pDC->SelectObject(&pen);
pDC->SelectObject(&brush);
// 移动到绘图起点
pDC->MoveToEx(50, 50, NULL);
// 绘制一条线到终点 (200, 200)
pDC->LineTo(200, 200);
// 清除选择的画笔和画刷,避免内存泄漏
pDC->SelectObject(&CPen::FromHandle((HPEN)GetStockObject(NULL_PEN)));
pDC->SelectObject(&CBrush::FromHandle((HBRUSH)GetStockObject(WHITE_BRUSH)));
}
在此代码段中,我们首先创建并选择了一个黑色的画笔和一个黄色的画刷到设备上下文。然后,我们使用 MoveToEx()
方法移动到绘图的起点,并用 LineTo()
方法绘制一条线段到指定的终点位置。完成绘图后,我们通过选择标准的空画笔和空画刷来清除之前选择的对象,确保不会产生内存泄漏。
4. 绘制三角形的Polygon()函数使用
4.1 Polygon()函数的基本用法
4.1.1 函数参数解析及多边形顶点的定义
在MFC(Microsoft Foundation Classes)中, Polygon()
函数被用于绘制由多个顶点构成的封闭多边形。其函数原型如下:
BOOL Polygon(LPPOINT lpPoints, int nCount);
-
lpPoints
:这是一个指向POINT
结构数组的指针,数组中的每个元素定义了多边形的一个顶点坐标。 -
nCount
:它表示顶点的数量。数组中必须至少包含三个顶点以构成一个三角形,而理论上顶点的最大数目没有限制。
Polygon()
函数将这些顶点按照数组顺序连接起来,并且自动将最后一个顶点与第一个顶点连接,形成封闭图形。
4.1.2 通过Polygon()绘制简单三角形
要绘制一个简单的三角形,首先需要定义三个顶点。下面是一个示例代码:
void CMyView::OnDraw(CDC* pDC)
{
CDocument* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// 定义三角形的三个顶点
POINT ptTriangle[3] = {
{100, 100}, // 三角形的第一个顶点
{100, 200}, // 三角形的第二个顶点
{200, 100} // 三角形的第三个顶点
};
// 使用Polygon()函数绘制三角形
pDC->Polygon(ptTriangle, 3);
}
在这段代码中, OnDraw()
函数首先定义了一个 POINT
数组,包含了三角形的三个顶点。然后通过调用 Polygon()
函数,并传递顶点数组和顶点数目,来绘制三角形。
4.2 高级三角形绘制技巧
4.2.1 如何创建闭合多边形
Polygon()
函数本身设计用于绘制闭合多边形。每个调用都会隐式地将最后一个顶点与第一个顶点相连。为了保证多边形正确闭合,开发者需要确保顶点数组的最后一个顶点坐标与第一个顶点坐标相同。如果第一个和最后一个顶点的坐标不同, Polygon()
函数会按照调用时的顺序连接它们,这可能产生不符合预期的图形。
4.2.2 利用Polygon()函数绘制复杂三角形结构
虽然 Polygon()
函数用于绘制多边形,但通过适当选择顶点,它可以用于绘制形状相似于三角形的复杂图形。例如,可以通过重复定义相同的顶点来创建具有多个凹面或凸面的形状。以下示例展示了如何绘制一个具有凹面的三角形:
void CMyView::OnDraw(CDC* pDC)
{
// 定义具有凹面的三角形顶点
POINT ptComplexTriangle[5] = {
{100, 100}, // 顶点1
{150, 200}, // 顶点2
{200, 100}, // 顶点3
{100, 100}, // 重复顶点1
{150, 50} // 顶点4,凹面顶点
};
// 使用Polygon()绘制复杂三角形结构
pDC->Polygon(ptComplexTriangle, 5);
}
在这个例子中,我们定义了四个顶点来形成一个三角形,并重复了顶点1与顶点4的坐标来实现凹面效果。通过这种技术,开发者可以创造出各种复杂而有趣的图形,以满足视觉和交互上的需求。
5. 扩展到绘制圆、椭圆、矩形等其他图形
在本章中,我们将继续探索CDC类提供的图形绘制功能,并扩展至绘制圆形、椭圆、矩形等其他图形。通过这些基本图形的绘制,开发者可以进一步理解CDC与GDI对象的协同工作,为创建更加复杂的用户界面元素打下坚实基础。
5.1 绘制圆形和椭圆形的函数应用
MFC框架通过CDC类封装了一系列的GDI函数,这些函数不仅能够绘制直线,还能绘制各种封闭的曲线图形。接下来,让我们详细了解如何使用这些函数来绘制圆形和椭圆形。
5.1.1 Arc()和Pie()函数绘制弧形和饼图
Arc()函数可以用来绘制一个椭圆弧线,而Pie()函数则是在Arc()的基础上进一步绘制一个“饼图”。这两个函数的使用需要指定椭圆的边界矩形、起始角度、终止角度等参数。
// 绘制一个椭圆弧线
void CMyView::DrawArc(CDC* pDC, CRect rect) {
pDC->Arc(rect.left, ***, rect.right, rect.bottom,
0, 180, 0, 360); // 从0度开始到180度结束
}
// 绘制一个饼图
void CMyView::DrawPie(CDC* pDC, CRect rect) {
pDC->Pie(rect.left, ***, rect.right, rect.bottom,
0, 180, 0, 360); // 从0度开始到180度结束
}
5.1.2 Ellipse()函数绘制椭圆形
Ellipse()函数是用于绘制椭圆形的。它需要四个参数:绘制椭圆的左上角和右下角坐标,这些坐标定义了一个矩形,椭圆将被绘制在这个矩形内。
// 绘制一个椭圆
void CMyView::DrawEllipse(CDC* pDC, CRect rect) {
pDC->Ellipse(rect);
}
5.2 矩形及其他图形的绘制方法
矩形是用户界面中最常见的图形之一,CDC类提供了Rectangle()函数来绘制矩形。此外,我们还可以使用Chord()函数绘制矩形内的弦形图形。
5.2.1 Rectangle()函数绘制矩形
Rectangle()函数用于绘制矩形或正方形。它接受四个参数,分别是矩形的左上角和右下角坐标。
// 绘制一个矩形
void CMyView::DrawRectangle(CDC* pDC, CRect rect) {
pDC->Rectangle(rect);
}
5.2.2 Chord()函数绘制弦形
Chord()函数用于绘制椭圆或圆内的一个弦形。它同样需要四个参数来定义边界矩形,加上起始和结束角度来定义弦形。
// 绘制一个弦形
void CMyView::DrawChord(CDC* pDC, CRect rect, int nStartAngle, int nEndAngle) {
pDC->Chord(rect, nStartAngle, nEndAngle);
}
总结本章,我们详细介绍了如何使用CDC类提供的多种函数绘制圆形、椭圆形、矩形以及弦形等图形。通过这些基础的图形绘制方法,开发者可以构建更加丰富的界面元素,并为更复杂的绘图需求打下基础。在下一章,我们将进一步探讨如何结合OnDraw()方法和鼠标事件,实现更加强大和交互式的绘图应用。
简介:MFC是一个C++库,封装了Windows API,用于高效构建Windows应用程序。本主题将演示如何使用MFC框架中的CDC类绘制直线和三角形,并扩展到绘制其他图形。CDC类提供了基本的绘图方法,如MoveTo()、LineTo()、Polygon()等。代码示例展示了如何在CView派生类中实现OnDraw()方法进行基本绘图,并覆盖鼠标事件以实现交互式图形绘制。熟练掌握MFC中的CDC和GDI是构建Windows图形界面的关键。