日落MFC-单文档GDI动态绘图

目录

GDI基础

MFC单文档绘图


这里主要记博主自己练手的一个小例子。

项目效果如图所示:

日落MFC-单文档GDI动态绘图_第1张图片

主要功能包括:画直线、画多段线、画椭圆、画矩形;鼠标单击Hittest点选所画图形并能进行平移、改色、计算面积/长度操作。

GDI基础


        GDI是Graphics Device Interface的缩写,含义是图形设备接口,它的主要任务是负责系统与绘图程序之间的信息交换,处理所有Windows程序的图形输出。

        在Windows操作系统下,绝大多数具备图形界面的应用程序都离不开GDI,我们利用GDI所提供的众多函数就可以方便的在屏幕、打印机及其它输出设备上输出图形,文本等操作。

GDI绘图基础:

  • 绘图画布--设备上下文(DC),解决在哪里画的问题
  • 绘图工具--GDI对象(CPen、CPoint等),解决用什么画的问题
  • 绘图函数--GDI绘图函数(Ellipse、Rectangle),解决怎么画问题

GDI绘图主要流程:

获取CDC,创建绘图工具、创建好点数据、定制好颜色,调用正确的函数。

 

MFC单文档绘图


         动态绘图主要技术点:

  • 重载OnLButtonDown,记录起始、终点数据
  • 重载OnLButtonUp,主要处理绘制标志位、更新多段线点位数据
  • 重载OnMouseMove,这里是实现动态画图的关键点,去描绘点位数据、画图形
  • 重载OnRButtonDown,主要是为了画多段线,多段线逻辑,鼠标每次单击确定多段线的一个点,鼠标右键单击结束绘制

        下面为核心点:

        以画直线为例,如果想看到单击鼠标左键定下起始点,拉动鼠标过程中直线动态画出的效果,就需要重载OnMouseMove,在其中不断的去画。我们在鼠标左键单击时记下直线起始点(记点A),而每次拖动鼠标都会触发OnMouseMove并传进来一个当前鼠标坐标点(记点B),在OnMouseMove中MoveTo(A),LineTo(B)即可画出一条直线。这样一来在真正的终点前会画无数条小的线段。但我们鼠标左键抬起时的点位才是真正的直线终点(记点C,它和OnLButtonUp前最后一次OnMouseMove的点B相同)。所以就需要在每次OnMouseMove中先把上一次画的线段清掉,再画新的,这样就画出了我们想要的直线。

        那么如何清掉上一次画的短线段呢?

       关键在于SetROP2函数,主要用于设定当前前景色的混合模式。调用SetROP2函数并传值R2_NOTXORPEN。R2_NOTXORPEN是C++中一种绘画模式,先把画笔颜色与屏幕颜色异或,之后再取反,最后得到一个颜色值显示在屏幕上。也就是说在使用R2_NOTXORPEN绘画模式时,用红色画笔在黑色背景上画一条直线,显示红色;但是当再次使用这只笔在刚画的直线上重画一遍时,就相当于把开始画的红线擦除掉了,划线的地方显示为背景色。

        代码如下:

        BOOL m_bSelecting;
	BOOL m_bDrawing;

	CPoint m_startPoint;
	CPoint m_oldPoint;

	std::vector m_vSelectPoints;
	std::vector m_vLinePoints;
	std::vector m_vPLPointsCell;
	std::vector> m_vPLPoints;
	std::vector m_vEllipsePoints;
	std::vector m_vRectPoints;

        afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
	afx_msg void OnRButtonDown(UINT nFlags, CPoint point);

      

void CDrawFiguresView::OnLButtonDown(UINT nFlags, CPoint point)
{
	if (m_bSelecting)
	{
		HittestPoint(point);
	}
	else
	{
		m_bDrawing = TRUE;
		m_startPoint = point;
		m_oldPoint = point;

		UpdateSrcPointsColl(point);
	}

	CView::OnLButtonDown(nFlags, point);
}


void CDrawFiguresView::OnLButtonUp(UINT nFlags, CPoint point)
{
	if (m_bDrawing)
	{
		if (m_eDrawType != DRAW_POLYLINE)
		{
			m_bDrawing = FALSE;
			UpdateSrcPointsColl(point);
		}
	}
	

	CView::OnLButtonUp(nFlags, point);
}


void CDrawFiguresView::OnMouseMove(UINT nFlags, CPoint point)
{
	if (TRUE == m_bDrawing)
	{
		CClientDC dc(this);
		CPen pen;
		pen.CreatePen(PS_SOLID, 2, m_Color);
		dc.SelectObject(pen);
		int oldRop = 0;
		switch (m_eDrawType)
		{
		case DRAW_LINE:
		{
			oldRop = dc.SetROP2(R2_NOTXORPEN);
			dc.MoveTo(m_startPoint);
			dc.LineTo(m_oldPoint);
			//dc.SetROP2(oldRop);
			dc.MoveTo(m_startPoint);
			dc.LineTo(point);
			break;
		}
		case DRAW_POLYLINE:
		{
			oldRop = dc.SetROP2(R2_NOTXORPEN);
			dc.MoveTo(m_startPoint);
			dc.LineTo(m_oldPoint);
			//dc.SetROP2(oldRop);
			dc.MoveTo(m_startPoint);
			dc.LineTo(point);
			break; 
		}			
		case DRAW_ELLIPSE:
		{
			//CBrush brush;
			//brush.CreateSolidBrush(m_BrushColor);
			//dc.SelectObject(brush);
			oldRop = dc.SetROP2(R2_NOTXORPEN);
			dc.Ellipse(m_startPoint.x, m_startPoint.y, m_oldPoint.x,m_oldPoint.y);
			//dc.SetROP2(oldRop);
			dc.Ellipse(m_startPoint.x, m_startPoint.y, point.x, point.y);
			break;
		}
		case DRAW_RECT:
		{
			//CBrush brush;
			//brush.CreateSolidBrush(m_BrushColor);
			//dc.SelectObject(brush);
			oldRop = dc.SetROP2(R2_NOTXORPEN);
			dc.Rectangle(CRect(m_startPoint, m_oldPoint));
			//dc.SetROP2(oldRop);
			dc.Rectangle(CRect(m_startPoint, point));
			break;
		}
		default:
			break;
		}

		m_oldPoint = point;
	}
	

	CView::OnMouseMove(nFlags, point);
}

void CDrawFiguresView::OnRButtonDown(UINT nFlags, CPoint point)
{
	if (m_bDrawing)
	{
		m_bDrawing = FALSE;
		if (DRAW_POLYLINE == m_eDrawType)
		{
			UpdateSrcPointsColl(point);
		}
		m_vPLPoints.push_back(m_vPLPointsCell);
		m_vPLPointsCell.clear();
	}
	CView::OnRButtonDown(nFlags, point);
}

 

 

 

 

 

 

 

你可能感兴趣的:(日落MFC)