标签:frame 用户 代码 意义 颜色 ext 记录 掌握 右键
这世界上有很多坑,注定有些坑是要填的。下面我就用VS2017使用MFC对这个课堂实验进行填坑。
一、实验目的
(1)掌握任意斜率直线段的重点 Bresenham 扫描转换算法;
(2)掌握 Cline 直线类的设计方法;
(3)掌握状态栏编程方法。
二、实验步骤
首先说一下目录结构,让大家对此有个清晰的了解:
这里我们只需要建立一个CLine类,里面的成员变量和成员函数具体意义如下:
在添加函数和变量时,有两种规范的方式:
①使用类视图的类向导,点击CLine类,右键菜单,类向导,这个方式一次性可添加CLine类的所有函数和变量。
②点击CLine类,右键菜单:添加->添加函数/添加变量,这个方式虽然要多次添加,但是可以添加注释。
步骤一:新建CLine类:
代码如下:
#pragma once class CLine { public: CLine(); virtual ~CLine(); private: // 直线斜率 double m_k; // 直线系数 double m_b; //直线起点 CPoint m_start; //直线终点 CPoint m_end; public: // 隐函数F(x,y)=y-kx-b,计算误差项 double getDistance(double x,double y); // 调用CDC对象的MoveTo(),移动到起点 void moveTo(CDC *&pDC); // 使用直线扫描算法绘制直线 void lineTo(CDC *&pDC); // 设置直线起点 void setStartPoint(CPoint point); // 设置直线终点 void setEndPoint(CPoint point); // 绘制直线斜率在0<k<1范围 void kOne(CDC *&pDC); // 绘制直线斜率在k>1范围 void kTwo(CDC *&pDC); // 绘制直线斜率在-1<k<0范围 void kThree(CDC *&pDC); // 绘制直线斜率在k<-1范围 void kFour(CDC *&pDC); };
CLine类的方法的具体实现( 使用Bresenham 扫描转换算法)。
#include "stdafx.h" #include "CLine.h" CLine::CLine() { } CLine::~CLine() { } // 隐函数F(x,y)=y-kx-b,计算误差项 double CLine::getDistance(double x,double y) { return y - m_k * x - m_b; } // 调用CDC对象的MoveTo(),移动到起点 void CLine::moveTo(CDC *&pDC) { pDC->MoveTo(m_start); } // 使用直线扫描算法绘制直线 void CLine::lineTo(CDC *&pDC) { //如果直线为垂线或是平行线或是k=1的直线 if ((m_end.x - m_start.x) == 0 || (m_end.y - m_start.y) == 0 || (m_end.x - m_start.x) == (m_end.y - m_end.y) || (m_end.x - m_start.x) == -(m_end.y - m_end.y)) pDC->LineTo(m_end); else { m_k = ((double)(m_end.y - m_start.y)) / (m_end.x - m_start.x); m_b = m_start.y - m_k * m_start.x; if (0 < m_k && m_k < 1) kOne(pDC); else if (m_k > 1) kTwo(pDC); else if (-1 < m_k && m_k < 0) kThree(pDC); else if (m_k < -1) kFour(pDC); } } // 设置直线起点 void CLine::setStartPoint(CPoint point) { this->m_end = point; } // 设置直线终点 void CLine::setEndPoint(CPoint point) { this->m_start = point; } // 绘制直线斜率在0<k<1范围 void CLine::kOne(CDC *&pDC) { //始终保持起点X坐标小于Y坐标 if (m_start.x > m_end.x) { CPoint tmp = m_start; m_start = m_end; m_end = tmp; } double d = 0; COLORREF color = RGB(0, 0, 0); //设置直线的颜色 CPoint next = m_start; //记录起始点 pDC->SetPixelV(next, color); //绘制起始点 for (int i = m_start.x + 1; i <= m_end.x; i++) { next.x++; //以X轴为主位移方向 if (d <= 0) //直线位于中点误差上方 next.y++; //取上面那个点 pDC->SetPixelV(next, color); //绘制点 d = getDistance((double)next.x + 1, next.y + 0.5); //下一个中点 } } // 绘制直线斜率在k>1范围 void CLine::kTwo(CDC *&pDC) { if (m_start.y > m_end.y) { CPoint tmp = m_start; m_start = m_end; m_end = tmp; } double d = 0; COLORREF color = RGB(0, 0, 0); CPoint next = m_start; pDC->SetPixelV(next, color); for (int i = m_start.y + 1; i <= m_end.y; i++) { next.y++; if (d > 0) next.x++; pDC->SetPixelV(next, color); d = getDistance(next.x + 0.5, (double)next.y + 1); } } // 绘制直线斜率在-1<k<0范围 void CLine::kThree(CDC *&pDC) { if (m_start.x < m_end.x) { CPoint temp = m_start; m_start = m_end; m_end = temp; } double d = 0; COLORREF color = RGB(0, 0, 0); CPoint next = m_start; pDC->SetPixelV(next, color); for (int i = m_start.x - 1; i >= m_end.x; i--) { next.x--; if (d < 0) next.y++; pDC->SetPixelV(next, color); d = getDistance((double)next.x - 1, next.y + 0.5); } } // 绘制直线斜率在k<-1范围 void CLine::kFour(CDC *&pDC) { if (m_start.y < m_end.y) { CPoint tmp = m_start; m_start = m_end; m_end = tmp; } double d = 0; COLORREF color = RGB(0, 0, 0); CPoint next = m_start; pDC->SetPixelV(next, color); for (int i = m_start.y - 1; i >= m_end.y; i--) { next.y--; if (d < 0) next.x++; pDC->SetPixelV(next, color); d = getDistance(next.x + 0.5, (double)next.y - 1); } }
步骤二:MFCApplication1View视图类中用类向导添加消息的处理程序:
①当左键鼠标按钮按下时,记录直线起点位置
void OnLButtonDown(UINT nFlags, CPoint point)
②当左键鼠标按钮松开时,记录直线终点位置并绘制直线
void OnLButtonUp(UINT nFlags, CPoint point)
③当鼠标移动时,在窗口用户区显示鼠标的x坐标和y坐标
void OnMouseMove(UINT nFlags, CPoint point)
④ 添加CLine类为成员变量
添加后,显示如下:
步骤三:CMainFrame类中CMFCStatusBar状态栏控件更改为共有成员变量。
步骤四:MFCApplication1View添加类的具体实现是方法。
在MFCApplication1View如图位置添加代码,
代码如下:
//当左键鼠标按钮按下时,记录直线起点位置 void CMFCApplication1View::OnLButtonDown(UINT nFlags, CPoint point) { this->line.setStartPoint(point); CView::OnLButtonDown(nFlags, point); } //当左键鼠标按钮松开时,记录直线终点位置并绘制直线 void CMFCApplication1View::OnLButtonUp(UINT nFlags, CPoint point) { this->line.setEndPoint(point); CDC *pDC = GetDC(); this->line.moveTo(pDC); this->line.lineTo(pDC); CView::OnLButtonUp(nFlags, point); } //当鼠标移动时,在窗口用户区显示鼠标的x坐标和y坐标 void CMFCApplication1View::OnMouseMove(UINT nFlags, CPoint point) { CString stringX, stringY; CMainFrame * pFrame = (CMainFrame *)AfxGetMainWnd(); CMFCStatusBar * pStatus = &pFrame->m_wndStatusBar; if (pStatus != NULL) { //_T是一个宏,作用是让你的程序支持Unicode编码(双字节编码) stringX.Format(_T("x=%d"), point.x); stringY.Format(_T("y=%d"), point.y); CClientDC dc(this); CSize sizeX = dc.GetTextExtent(stringX); CSize sizeY = dc.GetTextExtent(stringY); pStatus->SetPaneInfo(1, nFlags, SBPS_NORMAL, sizeX.cx); pStatus->SetPaneText(1, stringX); pStatus->SetPaneInfo(2, nFlags, SBPS_NORMAL, sizeY.cx); pStatus->SetPaneText(2, stringY); } CView::OnMouseMove(nFlags, point);
三、实验结果
运行后的实验结果如下:
①在空白Pane内可通过点击鼠标左键并移动鼠标松开左键的方式绘制直线
②右下角有显示鼠标的X坐标和Y坐标
图片1-1
标签:frame 用户 代码 意义 颜色 ext 记录 掌握 右键
原文地址:https://www.cnblogs.com/jdemarryme/p/8806752.html