【计算机图形学基础教程】MFC基本绘图函数2

MFC基本绘图函数

绘图工具类

  • CGdiObject类:GDI绘图工具的基类
  • CBitmap类:封装了GDI画刷,可以选作设备上下文的当前画刷,用于填充图形的内部
  • CFont类:封装了GDI字体,可以选作设备上下文的当前字体
  • CPalette类:封装了GDI调色板,提供应用程序和显示器之间的颜色接口
  • CPen类:封装了GDI画笔,可以选作设备上下文的当前画笔,用于绘制图形的边界线
  • CRgn类:封装了一个Windows的GDI区域,这一区域是某一个窗口的一个椭圆或多边形区域

选择GDI对象进行绘图,应遵循的步骤:

  1. 绘图开始前,创建一个新的GDI对象,并选入当前设备上下文,同时保存原GDI对象指针
  2. 使用新GDI对象绘图
  3. 绘图结束后,使用已保存的原GDI对象指针设备上下文恢复原状

映射模式

映射:将图形显示在屏幕坐标系的过程。
映射模式:逻辑坐标和设备坐标
逻辑坐标:单位是米制尺度或英制尺度
设备坐标:单位是像素

1. 设置映射模式函数

CDC::SetMapMode

// Mapping Functions
	virtual int SetMapMode(int nMapMode);

nMapMode为映射代码
设置映射模式,定义了将逻辑坐标转换为设备坐标的度量单位,并定义了设备坐标系的x轴和y轴方向

2. 设置窗口范围函数

CDC::SetWindowExt

	// Window extent
	virtual CSize SetWindowExt(int cx, int cy);
			CSize SetWindowExt(SIZE size);

cx, cy窗口x, y范围的逻辑坐标,size是窗口的SIZE结构或CSize对象

3. 设置视区范围函数

CDC::SetViewportExt

	// Viewport Extent
	virtual CSize SetViewportExt(int cx, int cy);
			CSize SetViewportExt(SIZE size);

cx, cy窗口x, y范围的逻辑坐标,size是窗口的SIZE结构或CSize对象

4. 设置窗口原点函数

CDC::SetWindowOrg

	// Window Origin
	CPoint SetWindowOrg(int x, int y);
	CPoint SetWindowOrg(POINT point);

x, y窗口新原点坐标,point是窗口新原点的POINT结构或CPoint对象

5. 设置视区原点函数

CDC::SetViewportOrg

	// Viewport Origin
	virtual CPoint SetViewportOrg(int x, int y);
			CPoint SetViewportOrg(POINT point);

x, y窗口新原点坐标,point是窗口新原点的POINT结构或CPoint对象

映射代码

各向同性MM_ISOTROPIC和各向异性MM_ANISOTROPIC,需调用SetWindowExt()和SetViewportExt()来改变窗口和视区的设置

MM_ISOTROPIC: 要求x轴和y轴比例相等,以保持图形形状不发生变化
MM_ANISOTROPIC: 可以改变坐标系的单位、方向和比例

窗口与视区

窗口:可以理解为一种逻辑坐标系下的矩形区域
视区:是设备坐标系下的矩形区域

x方向比例因子 = 视区cx / 窗口cx
y方向比例因子 = 视区cy / 窗口cy

例子1:

SetWindowExt(100, 100);
SetViewportExt(200, 200);

x,y方向的比例因子为2, 说明窗口的一个逻辑坐标映射为视区的两个像素。
绘制100×100逻辑坐标的正方形,结果为200×200像素的正方形

例子2:

SetWindowExt(100, 200);
SetViewportExt(200, 200);

x方向的比例因子为2, y方向的比例因子为1,说明窗口x方向的一个逻辑坐标映射为视区的两个像素,窗口y方向的一个逻辑坐标映射为视区的一个像素
绘制100×100逻辑坐标的正方形,结果为200×100像素的正方形

例子3:
使用用户自定义映射模式,设置窗口大小和视区大小相等的二维坐标系。视区中x轴水平向右为正,y轴垂直向上为正,原点位于屏幕客户区中心。

void CMFCTestView::OnDraw(CDC* pDC)
{
	CMFCTestDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO:  在此处为本机数据添加绘制代码
	pDC->TextOutW(600, 100, _T("Hello there!"));
	CRect rect;    // 定义矩形
	GetClientRect(&rect);    // 获得客户区矩形
	pDC->SetMapMode(MM_ANISOTROPIC);    // 设置映射模式
	pDC->SetWindowExt(rect.Width(), rect.Height());     // 设置窗口
	pDC->SetViewportExt(rect.Width(), -rect.Height());   // 设置视区:x轴水平向右为正,y轴垂直向上为正
	pDC->SetViewportOrg(rect.Width()/2, rect.Height()/2);   // 设置客户区中心点为坐标系原点
	rect.OffsetRect(-rect.Width()/2, -rect.Height()/2);    // 客户区矩形校正
	pDC->TextOutW(600, 100, _T("Hello there!"));

在这里插入图片描述
可以看到变换了坐标系之后,在输入相同的坐标位置的文字时,文字会在屏幕不同的位置打印出来,这是因为对坐标系进行了变换(原点从左上角平移到中+上下翻转)。

使用GDI对象

1. 创建画笔函数

画笔属性:线型、宽度和颜色
画笔的线型:实线、虚线、点线、点划线、双点划线、不可见线和内框架线,PS_为前缀
画笔的宽度:用像素表示
画笔的颜色:RGB宏表示

CPen::CreatePen

BOOL CreatePen(int nPenStyle, int nWidth, COLORREF crColor);
BOOL CreatePen(int nPenStyle, int nWidth, const LOGBRUSH* pLogBrush,
		int nStyleCount = 0, const DWORD* lpStyle = NULL);

nPenStyle是画笔样式,nWidth是画笔宽度,crColor是画笔颜色

typedef DWORD   COLORREF;

2. 创建画刷函数

仅对绘制的闭合图形有效

CBrush::CreateSolidBrush:

BOOL CreateSolidBrush(COLORREF crColor);

实体画刷,用指定的颜色填充图形内部

CBrush::CreateHatchBrush:

BOOL CreateHatchBrush(int nIndex, COLORREF crColor);

使用指定的阴影样式和颜色填充图形内部, HS前缀

CBrush::CreatePatternBrush:

BOOL CreatePatternBrush(CBitmap* pBitmap);

使用位图创建一个逻辑画刷

3. 选入GDI对象

CDC::SelectObject

	CPen* SelectObject(CPen* pPen);
	CBrush* SelectObject(CBrush* pBrush);
	virtual CFont* SelectObject(CFont* pFont);
	CBitmap* SelectObject(CBitmap* pBitmap);
	int SelectObject(CRgn* pRgn);       // special return for regions
	CGdiObject* SelectObject(CGdiObject* pObject);

pPen是将要选择的画笔对象指针
pBrush是将要选择的画刷对象指针
pBitmap是将要选择的位图对象指针

4. 删除GDI对象

CGdiObject::DeleteObject

BOOL DeleteObject();

5. 选入库对象

使用完库画笔和画刷不需要调用DeleteObject()函数从内存中删除

CDC::SelectStockObject

virtual CGdiObject* SelectStockObject(int nIndex);

CDC类绘图成员函数

1. 绘制像素点函数

CDC::SetPixel和CDC::SetPixelV

	COLORREF SetPixel(int x, int y, COLORREF crColor);
	COLORREF SetPixel(POINT point, COLORREF crColor);
	BOOL SetPixelV(int x, int y, COLORREF crColor);
	BOOL SetPixelV(POINT point, COLORREF crColor);

SetPixel()返回绘制像素点的RGB值,SetPixelV不需要返回所绘制像素点的RGB值

2. 获取像素点颜色函数

CDC::GetPixel

	COLORREF GetPixel(int x, int y) const;
	COLORREF GetPixel(POINT point) const;

返回指定像素的RGB值

例子4:

在屏幕上使用SetPixelV()函数将crColor参数设置为随机颜色,用像素点在x轴负向画出对角点为(-150, -50)和(-50, 50)的正方形。然后使用GetPixel()函数依次读出该正方形内各像素点的颜色,在x轴正向的对称位置上重新绘制该正方形

void CMFCTestView::OnDraw(CDC* pDC)
{
	CMFCTestDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO:  在此处为本机数据添加绘制代码
	CRect rect;    // 定义矩形
	GetClientRect(&rect);    // 获得客户区矩形
	pDC->SetMapMode(MM_ANISOTROPIC);    // 设置映射模式
	pDC->SetWindowExt(rect.Width(), rect.Height());     // 设置窗口
	pDC->SetViewportExt(rect.Width(), -rect.Height());   // 设置视区:x轴水平向右为正,y轴垂直向上为正
	pDC->SetViewportOrg(rect.Width()/2, rect.Height()/2);   // 设置客户区中心点为坐标系原点
	rect.OffsetRect(-rect.Width()/2, -rect.Height()/2);    // 客户区矩形校正
	srand((unsigned)time(NULL));   // 使用系统时间初始化随机种子,使得每次产生不同的随机数
	COLORREF crColor;              // 用于存放像素点的颜色值
	int x, y;                      // 像素点的位置坐标
	for (y = -50; y < 50; y++)
	{
		for (x = -150; x < -50; x++)
		{
			// 用随机颜色在x轴负向绘制对角点(-150, -50)和(-50, 50)的正方形
			pDC->SetPixelV(x, y, RGB(rand() % 255, rand() % 255, rand() % 255));  
		}
	}
	for (y = -50; y < 50; y++)
	{
		for (x = -150; x < -50; x++)
		{
			crColor = pDC->GetPixel(x, y);   // 先读取对角点(-150, -50)和(-50, 50)的正方形的像素点的颜色
			pDC->SetPixelV(-x, y, crColor);  // 关于y轴对称位置绘制
		}
	}

	
}

在这里插入图片描述

3. 绘制直线段函数

配合使用MoveTo()和LineTo()函数
每次绘制直线以当前位置为起点,绘制结束后,终点成为当前位置。

CDC::MoveTo

	CPoint MoveTo(int x, int y);
	CPoint MoveTo(POINT point);

设置当前位置函数,只将画笔的当前位置移动到坐标x和y处,不画线

CDC::LineTo

	BOOL LineTo(int x, int y);
	BOOL LineTo(POINT point);

绘制直线段函数,从当前位置绘制直线段,但不包括(x,y)点

例5:

从起点p0(-100, -50)到终点p1(100, 50)绘制一段1像素宽的蓝色直线。

void CMFCTestView::OnDraw(CDC* pDC)
{
	CMFCTestDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO:  在此处为本机数据添加绘制代码
	CRect rect;    // 定义矩形
	GetClientRect(&rect);    // 获得客户区矩形
	pDC->SetMapMode(MM_ANISOTROPIC);    // 设置映射模式
	pDC->SetWindowExt(rect.Width(), rect.Height());     // 设置窗口
	pDC->SetViewportExt(rect.Width(), -rect.Height());   // 设置视区:x轴水平向右为正,y轴垂直向上为正
	pDC->SetViewportOrg(rect.Width()/2, rect.Height()/2);   // 设置客户区中心点为坐标系原点
	rect.OffsetRect(-rect.Width()/2, -rect.Height()/2);    // 客户区矩形校正

	CPoint p0(-100, -50), p1(100, 50);               // 定义直线段的起点和终点
	CPen NewPen, *pOldPen;                      
	NewPen.CreatePen(PS_SOLID, 1, RGB(0, 0, 255));    // 创建蓝色实线画笔, RGB:0xff0000
	pOldPen = pDC->SelectObject(&NewPen);             // 将新画笔选入设备上下文,同时用pOldPen指针保存原画笔指针
	pDC->MoveTo(p0);                                 // 将当前位置移动到直线段起点
	pDC->LineTo(p1);                                // 从起点绘制直线段直到终点
	pDC->SelectObject(pOldPen);                     // 新画笔使用完毕后,用pOldPen指针保存的原画笔将设备上下文恢复原状
}

在这里插入图片描述

4. 绘制矩形函数

CDC::Rectangle

	BOOL Rectangle(int x1, int y1, int x2, int y2);
	BOOL Rectangle(LPCRECT lpRect);

绘制直角矩形,使用当前画刷填充直角矩形内部,并使用当前画笔绘制直角矩形边界线

CDC::RoundRect

	BOOL RoundRect(int x1, int y1, int x2, int y2, int x3, int y3);
	BOOL RoundRect(LPCRECT lpRect, POINT point);

绘制圆角矩形,使用当前画刷填充圆角矩形内部,并使用当前画笔绘制圆角矩形边界线

CDC::SetPolyFillMode

	int SetPolyFillMode(int nPolyFillMode);

设置填充模式函数,有ALTERNATE和WINDING模式

  • ALTERNATE:按照扫描线填充相邻的奇偶边内的区域,五角星只填充五角星的五个角,不填充五角星内部的五边形
  • WINDING:根据边的绘制方向(顺时针或逆时针)来决定是否填充多边形内部,从图形内部向外引一条假想直线,遇到顺时针绘制的边计数器加1,遇到逆时针绘制的边计数器减1,计数器不为0时,填充该区域。内部五边形引出假想直线,遇到两条逆时针绘制的边,计数器为-2; 五角星的角内引出假想的边,遇到一条逆时针的边,计数器为-1。两种情况计数器均不为0, 所以WINDING模式填充整个五角星

例6:

将客户区矩形上下左右边界各收缩100个像素绘制重叠的方角矩形和圆角矩形。矩形边框为1的像素宽的蓝色边界线。方角矩形内部使用默认画刷填充,圆角矩形内部填充红色,圆角取为(200, 200)

void CMFCTestView::OnDraw(CDC* pDC)
{
	CMFCTestDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO:  在此处为本机数据添加绘制代码
	CRect rect;    // 定义矩形
	GetClientRect(&rect);    // 获得客户区矩形
	pDC->SetMapMode(MM_ANISOTROPIC);    // 设置映射模式
	pDC->SetWindowExt(rect.Width(), rect.Height());     // 设置窗口
	pDC->SetViewportExt(rect.Width(), -rect.Height());   // 设置视区:x轴水平向右为正,y轴垂直向上为正
	pDC->SetViewportOrg(rect.Width()/2, rect.Height()/2);   // 设置客户区中心点为坐标系原点
	rect.OffsetRect(-rect.Width()/2, -rect.Height()/2);    // 客户区矩形校正

	rect.DeflateRect(100, 100);                      // 将矩形两个方向都缩小100个像素
	CPen NewPen, *pOldPen;
	NewPen.CreatePen(PS_SOLID, 1, RGB(0, 0, 255));  // 创建蓝色实线画笔, RGB:0xff0000
	pOldPen = pDC->SelectObject(&NewPen);           // 将新画笔选入设备上下文,同时用pOldPen指针保存原画笔指针
	pDC->Rectangle(rect);                           // 绘制方角矩形
	CBrush NewBrush, *pOldBrush;
	NewBrush.CreateSolidBrush(RGB(255, 0, 0));      // 创建红色画刷
	pOldBrush = pDC->SelectObject(&NewBrush);       // 将新画刷选入设备上下文,同时用pOldBrush指针保存原画刷指针
	pDC->RoundRect(rect, CPoint(200, 200));         // 绘制圆角矩形
	pDC->SelectObject(pOldPen);
	pDC->SelectObject(pOldBrush);
}

在这里插入图片描述

CDC::FillRect

	void FillRect(LPCRECT lpRect, CBrush* pBrush);

画刷填充矩形函数,使用当前话术填充整个矩形,包括左边界和上边界,但不包括右边界和下边界

CDC::FillSolidRect

	void FillSolidRect(LPCRECT lpRect, COLORREF clr);
	void FillSolidRect(int x, int y, int cx, int cy, COLORREF clr);

FillSolidRect()函数颜色填充矩形函数,仅使用颜色填充矩形;FillRect()函数则可以使用阴影图案填充矩形

例7:

以(-250, 50)为左下角点,以(250, 150)为右上角点绘制矩形,使用红色HS_BDIANGONAL阴影模式填充。以(-250, -150)为左下角点,以(250, -50)为右上角点绘制矩形,使用红色填充

void CMFCTestView::OnDraw(CDC* pDC)
{
	CMFCTestDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO:  在此处为本机数据添加绘制代码
	CRect rect;    // 定义矩形
	GetClientRect(&rect);    // 获得客户区矩形
	pDC->SetMapMode(MM_ANISOTROPIC);    // 设置映射模式
	pDC->SetWindowExt(rect.Width(), rect.Height());     // 设置窗口
	pDC->SetViewportExt(rect.Width(), -rect.Height());   // 设置视区:x轴水平向右为正,y轴垂直向上为正
	pDC->SetViewportOrg(rect.Width()/2, rect.Height()/2);   // 设置客户区中心点为坐标系原点
	rect.OffsetRect(-rect.Width()/2, -rect.Height()/2);    // 客户区矩形校正

	CRect rect1(CPoint(-250, 50), CPoint(250, 150));
	CRect rect2(CPoint(-250, -150), CPoint(250, -50));
	CBrush Brush(HS_BDIAGONAL, RGB(255, 0, 0));     // 定义红色阴影画刷
	pDC->FillRect(&rect1, &Brush);                  // 阴影填充矩形
	pDC->FillSolidRect(&rect2, RGB(255, 0, 0));     // 红色填充矩形
}

在这里插入图片描述

5. 绘制椭圆函数

CDC::Ellipse

	BOOL Ellipse(int x1, int y1, int x2, int y2);
	BOOL Ellipse(LPCRECT lpRect);

使用当前画刷填充椭圆内部,并使用当前画笔绘制椭圆边界线;圆= 长半轴和短半轴相等椭圆,lpRect是确定椭圆范围的外接矩形

例8

将客户区矩形上下左右边界各收缩100像素,分别绘制矩形、矩形内切圆和矩形内切椭圆。绘制过程按圆、椭圆和矩形顺序完成。设定圆、椭圆和矩形的边界线为1像素宽黑色实现,内部全部使用透明画刷填充

void CMFCTestView::OnDraw(CDC* pDC)
{
	CMFCTestDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO:  在此处为本机数据添加绘制代码
	CRect rect;    // 定义矩形
	GetClientRect(&rect);    // 获得客户区矩形
	pDC->SetMapMode(MM_ANISOTROPIC);    // 设置映射模式
	pDC->SetWindowExt(rect.Width(), rect.Height());     // 设置窗口
	pDC->SetViewportExt(rect.Width(), -rect.Height());   // 设置视区:x轴水平向右为正,y轴垂直向上为正
	pDC->SetViewportOrg(rect.Width()/2, rect.Height()/2);   // 设置客户区中心点为坐标系原点
	rect.OffsetRect(-rect.Width()/2, -rect.Height()/2);    // 客户区矩形校正

	rect.DeflateRect(100, 100);                      // 将矩形两个方向都缩小100个像素,返回的类型是CGdiObject*, 需要强制转换为CBrush*
	CBrush *pOldBrush;
	pOldBrush = (CBrush*)pDC->SelectStockObject(NULL_BRUSH);   // 选择透明画刷
	int r = rect.Height() / 2;            // 定义圆的半径
	CRect rect1(CPoint(-r, -r), CPoint(r, r));    // 定义圆的外接矩形
	pDC->Ellipse(rect1);            // 绘制圆
	pDC->Ellipse(rect);             // 绘制椭圆
	pDC->Rectangle(rect);           // 绘制外接矩形
	pDC->SelectObject(pOldBrush);    
}

在这里插入图片描述

6. 绘制椭圆弧函数

CDC::Arc

	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);

椭圆弧的真实起点是外接矩形中心点与(x3,y3)(或ptStart)点所构成的射线与椭圆的交点;椭圆弧的真实终点是外接矩形中心与(x1,y1)(或ptEnd)点所构成的射线与椭圆的交点。

例9

在客户区内从12点到3点位置逆时针绘制黑色点划线椭圆弧,从12点到3点位置顺时针绘制蓝色实现椭圆弧

void CMFCTestView::OnDraw(CDC* pDC)
{
	CMFCTestDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO:  在此处为本机数据添加绘制代码
	CRect rect;    // 定义矩形
	GetClientRect(&rect);    // 获得客户区矩形
	pDC->SetMapMode(MM_ANISOTROPIC);    // 设置映射模式
	pDC->SetWindowExt(rect.Width(), rect.Height());     // 设置窗口
	pDC->SetViewportExt(rect.Width(), -rect.Height());   // 设置视区:x轴水平向右为正,y轴垂直向上为正
	pDC->SetViewportOrg(rect.Width()/2, rect.Height()/2);   // 设置客户区中心点为坐标系原点
	rect.OffsetRect(-rect.Width()/2, -rect.Height()/2);    // 客户区矩形校正


	CPoint Twelve(0, rect.Height() / 2), Three(rect.Width() / 2,  0);  // 定义12点和3点的位置
	CPen penBlack, penBlue, *pOldPen;
	penBlue.CreatePen(PS_SOLID, 1, RGB(0, 0, 255));    // 蓝色实线画笔
	penBlack.CreatePen(PS_DASHDOT, 1, RGB(0, 0, 0));    // 黑色点划线画笔
	pDC->SetArcDirection(AD_CLOCKWISE);      // 顺时针绘制12点到3点的椭圆形
	pOldPen = pDC->SelectObject(&penBlue);    
	pDC->Arc(rect, Twelve, Three);            // 绘制椭圆形
	pDC->SetArcDirection(AD_COUNTERCLOCKWISE);     // 逆时针绘制12点到3点的椭圆形
	pOldPen = pDC->SelectObject(&penBlack);
	pDC->Arc(rect, Twelve, Three);     
	pDC->SelectObject(pOldPen);
}

在这里插入图片描述

7. 绘制扇形函数

CDC::Pie

	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);

扇形中心位置坐标是外接矩形的中心,扇形从起点到终点逆时针方向绘制,扇形直接用直线段连接扇形中心与扇形的起点和终点

例10

绘制两个扇形构成扇子形状,使用位图画刷填充扇子内部

void CMFCTestView::OnDraw(CDC* pDC)
{
	CMFCTestDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO:  在此处为本机数据添加绘制代码
	CRect rect;    // 定义矩形
	GetClientRect(&rect);    // 获得客户区矩形
	pDC->SetMapMode(MM_ANISOTROPIC);    // 设置映射模式
	pDC->SetWindowExt(rect.Width(), rect.Height());     // 设置窗口
	pDC->SetViewportExt(rect.Width(), -rect.Height());   // 设置视区:x轴水平向右为正,y轴垂直向上为正
	pDC->SetViewportOrg(rect.Width()/2, rect.Height()/2);   // 设置客户区中心点为坐标系原点
	rect.OffsetRect(-rect.Width()/2, -rect.Height()/2);    // 客户区矩形校正

	CBitmap NewBitmap;
	NewBitmap.LoadBitmap(IDB_BITMAP1);            // 导入位图
	CBrush NewBrush, *pOldBrush;
	NewBrush.CreatePatternBrush(&NewBitmap);     // 创建位图画刷
	pOldBrush = pDC->SelectObject(&NewBrush);
	CPen * pOldPen;
	pOldPen = (CPen*)pDC->SelectStockObject(NULL_PEN);   // 选入透明库画笔,不绘制扇形的边界线
	CPoint ld, rt, sp, ep;
	ld = CPoint(-400, -600), rt = CPoint(400, 200);  // 外接矩形的左下角ld,右上角rt, 椭圆弧的起点sp和终点ep

	sp = CPoint(400, 0), ep = CPoint(-400, 0);
	pDC->Pie(CRect(ld, rt), sp, ep);    
	pDC->SelectObject(pOldBrush);                       // 更换位图画刷
	NewBitmap.DeleteObject();                           // 删除位图

	ld = CPoint(-80, -280), rt = CPoint(80, -120);      //绘制扇子的内扇形
	sp = CPoint(400, 0), ep = CPoint(-400, 0);
	pDC->Pie(CRect(ld, rt), sp, ep);                 // 使用白色的默认画刷填充
	pDC->SelectObject(pOldPen);                      // 恢复原画笔
}

在这里插入图片描述

其中,导入位图步骤如下:

  1. 在解决方案资源管理图找到MFCTest.rc, 双击:
    在这里插入图片描述
  2. 进入资源视图,右击MFCTest.rc,选择添加资源:
    在这里插入图片描述
  3. 选中Bitmap, 点击导入:
    在这里插入图片描述
  4. 选择bmp文件:
    在这里插入图片描述
  5. 即可看到IDB_BITMAP1被加载到Bitmap里:
    在这里插入图片描述

8. 绘制多边形函数

CDC::Polygon

	BOOL Polygon(const POINT* lpPoints, int nCount);	

使用当前画刷填充多边形内部,并使用当前画笔绘制多边形边界线

例11

以正五边形的5个顶点为基础,隔点存储构成五角星,p0p4为五边形的5个顶点,v0v4为五角星的5个顶点。填充模式采用WINDING。五角星边界线为5个像素宽的蓝色实线,内部使用红色填充。

void CMFCTestView::OnDraw(CDC* pDC)
{
	CMFCTestDoc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;

	// TODO:  在此处为本机数据添加绘制代码
	CRect rect;    // 定义矩形
	GetClientRect(&rect);    // 获得客户区矩形
	pDC->SetMapMode(MM_ANISOTROPIC);    // 设置映射模式
	pDC->SetWindowExt(rect.Width(), rect.Height());     // 设置窗口
	pDC->SetViewportExt(rect.Width(), -rect.Height());   // 设置视区:x轴水平向右为正,y轴垂直向上为正
	pDC->SetViewportOrg(rect.Width()/2, rect.Height()/2);   // 设置客户区中心点为坐标系原点
	rect.OffsetRect(-rect.Width()/2, -rect.Height()/2);    // 客户区矩形校正


	CPen penBlue(PS_SOLID, 5, RGB(0, 0, 0255));     // 定义5个像素宽的蓝色画笔
	CPen *pOldPen = pDC->SelectObject(&penBlue); 
	CBrush brushRed(RGB(255, 0, 0));    // 定义红色画刷
	CBrush * pOldBrush = pDC->SelectObject(&brushRed);  
	pDC->SetPolyFillMode(WINDING);   // 设置填充模式
	int r = 200;            // 设置五边形外接圆半径
	CPoint p[5];            // 设置正五边形顶点数据
	double Beta = 2 * PI / 5;  // 定义每个顶点的圆心角
	double Alpha = PI / 10;   // 定义起始角, 18°起始角正好将五角星放正

	for (int i = 0; i < 5; i++)
	{
		p[i].x = Round(r*cos(i*Beta + Alpha));    // 计算正五边形顶点坐标
		p[i].y = Round(r*sin(i*Beta + Alpha));
	}
	CPoint v[5];   // 定义五角星顶点数组
	v[0] = p[0];    // 将正五边形的顶点数组转储为五角星的顶点数组
	v[1] = p[2];
	v[2] = p[4];
	v[3] = p[1];
	v[4] = p[3];    // 转储顶点
	pDC->Polygon(v, 5);    //绘制五角星
	pDC->SelectObject(pOldPen);   // 恢复画笔
	pDC->SelectObject(pOldBrush);  // 恢复画刷
}

在这里插入图片描述
采用ALTERNATE模式:
在这里插入图片描述
参考:
孔令德, 计算机图形学基础教程(Visual C++版)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.kler.cn/a/18512.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

selenium——unittest框架

目录 一、unittest框架基本介绍二、unittest框架解析三、unittest框架使用方法1.测试固件2.测试套件3.用例的执行顺序4.忽略测试用例中的方法5.unittest断言6.HTML报告生成 一、unittest框架基本介绍 在进行selenium IDE脚本录制导出的脚本中&#xff0c;我们发现其中多了很多…

基于 EKS Fargate 搭建微服务性能分析系统

背景 近期 Amazon Fargate 在中国区正式落地&#xff0c;因 Fargate 使用 Serverless 架构&#xff0c;更加适合对性能要求不敏感的服务使用&#xff0c;Pyroscope 是一款基于 Golang 开发的应用程序性能分析工具&#xff0c;Pyroscope 的服务端为无状态服务且性能要求不敏感&…

mysql数据迁移与同步常用解决方案总结

目录 一、前言 二、数据迁移场景 2.1 整库迁移 2.2 表数据迁移 2.3 mysql版本变更 2.4 mysql数据迁移至其他存储介质 2.5 自建数据到上云环境 2.6 mysql数据到其他国产数据库 三、数据库物理迁移实施方案 3.1 数据库物理迁移概述 3.1.1 物理迁移适用场景 3.1.2 物理…

TCP三次握手

TCP三次握手 文章目录 TCP三次握手1. TCP三次握手过程和状态变迁1. 准备工作2. 进行连接 2. 能把三次握手改为两次握手吗&#xff1f;3. 改为两次握手会出现什么后果&#xff1f;4. 改为四次握手行不行&#xff1f;5. TCP第三次握手失败了怎么办&#xff1f;6. 三次握手是否可以…

TCP四次挥手

TCP四次挥手详解 文章目录 TCP四次挥手详解1. TCP四次挥手过程和状态变迁2. 为什么挥手需要四次&#xff1f;3. 为什么中间的ACK和FIN不可以像三次握手那样合为一个报文段呢&#xff1f;4. 为什么TIME_WAIT等待的时间是2MSL&#xff1f;5. 等待2MSL的意义5.1 保证客户端最后发送…

Linux网络——Shell编程之数组

Linux网络——Shell编程之数组 一、概念二、数组的定义三、Shell数组操作1. 获取数组的所有元素的列表2. 获取数组的所有元素下标3.取数组的元素个数4. 获取数组的某个元素的值5.删除数组某个元素6.删除数组7.数组切片8.数组字符替换9.数组追加元素 四、数组在函数的传参 一、概…

天猫数据分析:2023年Q1天猫净水器品牌销售TOP10排行榜

水质的好坏更是与人们的身体健康密切相关。随着社会经济的发展&#xff0c;居民生活水平提升&#xff0c;人们对饮用水质量、安全性的要求也不断提高&#xff0c;净水器也因此逐渐成为现代生活的必需品。 根据鲸参谋电商数据显示&#xff0c;2023年Q1在天猫平台上&#xff0c;净…

3. SQL底层执行原理详解

一条SQL在MySQL中是如何执行的 1. MySQL的内部组件结构1.1 Server层1.2 Store层 2. 连接器3. 分析器4. 优化器5. 执行器6. bin-log归档 本文是按照自己的理解进行笔记总结&#xff0c;如有不正确的地方&#xff0c;还望大佬多多指点纠正&#xff0c;勿喷。 1. MySQL的内部组件结…

MVC分部视图的使用:Html.Partial/RenderPartial,Html.Action/RenderAction,RenderPage

ASP.NET MVC 里的部分视图&#xff0c;相当于 Web Form 里的 User Control。我们的页面往往会有许多重用的地方&#xff0c;可以进行封装重用。 使用部分视图有以下优点&#xff1a; 1. 可以简写代码。 2. 页面代码更加清晰、更好维护。 在视图里有多种方法可以 加载部分视图&a…

硬盘数据突然消失怎么回事?硬盘数据突然消失怎么找回

硬盘上的数据对每个人都至关重要&#xff0c;它可能是我们的珍贵回忆&#xff0c;多年学习的总结&#xff0c;或者一些不可告人的秘密。而硬盘中的数据可能会在不知情的情况下消失或被删除&#xff0c;这种情况对我们来说十分痛苦和困扰。然而&#xff0c;我们不必担心&#xf…

如何用100天彻底学会Python?

Python 是一门功能强大、易于学习且历史悠久的编程语言。如果你希望在短时间内彻底学会 Python&#xff0c;需要制定一个全面的学习计划&#xff0c;并进行刻意的练习和实践。 以下是一份建议的学习计划&#xff0c;帮助你在 100 天内掌握 Python 技能。 第 1-10 天&#xff…

JavaScript class和继承的原理

&#xff08;对于不屈不挠的人来说&#xff0c;没有失败这回事。——俾斯麦&#xff09; class 相关链接 MDN链接 有关类的详细描述 关于构造函数&#xff0c;原型和原型链的说明 类的概述 类是用于创建对象的模板。他们用代码封装数据以处理该数据。JS 中的类建立在原型上…

【Queue新技法】用双数组实现一个队列 C++

目录 1 常规的队列构建2 加入一些限制2-1形式化说明2-2 优化&#xff1a;平衡队列 附录0 双数组或双链表实现队列1 单链表与循环缓冲区实现队列3 参考资料 1 常规的队列构建 到火车站办理退票&#xff0c;排队的人构成队列。注意到有两个关键动作&#xff1a; 入队&#xff0c…

C++类和对象(上)

目录 一、类 1.1 类的引入 1.2 类的定义 1.3 类的访问限定符及封装 1.3.1 类的访问限定符 1.3.2 封装 1.4 类定义方式 1.4.1 声明和定义都放在类体里 1.4.2 类可以声明和定义分离 1.5 类的作用域 1.6 类的实例化 1.6.1 定义 1.6.2 计算类对象的大小 二、this指针…

华为OD机试真题 Java 实现【猜字谜】【2023Q2】

一、题目描述 小王设计了一人简单的清字谈游戏&#xff0c;游戏的迷面是一人错误的单词&#xff0c;比如nesw&#xff0c;玩家需要猜出谈底库中正确的单词。猜中的要求如 对于某个谜面和谜底单词&#xff0c;满足下面任一条件都表示猜中&#xff1a; 变换顺序以后一样的&…

【MySQL】索引

之前的select所采用的方式是遍历数据表进行查找,这种方式效率是比较低的,尤其是数据表汇总数据量比较大的时候,于是便有了索引,MySQL中的索引的作用就是为了快速获取数据 文章目录 1.索引简介2.索引的数据结构2.1 B-Tree2.2 Hash索引 3.索引的分类4.索引的语法5.SQL性能分析6.…

字节跳动发放年终奖,远超预期~

最近一段时间&#xff0c;国内互联网大厂接连公布年终奖情况&#xff0c;整个后厂村都洋溢在春节般的喜庆气氛里。 虽然由于各种各样的顾虑&#xff08;主要是人员流失问题&#xff09;&#xff0c;大部分公司都将年终奖发放时间调整到了年中&#xff0c;但好饭不怕晚&#xf…

Java笔记_17(异常、File)

Java笔记_17 一、异常1.1、异常体系介绍1.2、编译时异常和运行时异常1.3、异常的作用1.4、异常的处理方式1.5、捕获异常的灵魂四问1.6、异常中的常见方法1.7、抛出处理1.8、异常-练习&#xff08;键盘录入数据&#xff09;1.9、自定义异常 二、File2.1、File的概述和构造2.2、F…

uboot 启动内核代码分析

0、uboot和内核区别 uboot的本质就是一个复杂点的裸机程序。内核本身也是一个"裸机程序“&#xff0c;和uboot、和其他裸机程序并没有本质区别。 区别就是操作系统运行起来后在软件上分为内核层和应用层&#xff0c;分层后两层的权限不同&#xff0c;在内存访问和设备操作…

离散化(算法)

目录 一、离散化的概念二、离散化的模板三、离散化的应用题目思路分析代码实现 一、离散化的概念 离散化是一种将连续数据映射到离散值的过程。它通常用于优化某些算法&#xff0c;尤其是与区间查询相关的问题。 在离散化过程中&#xff0c;我们将一组实数转换为一组整数&#…
最新文章