概述
目录
GDI基础
MFC单文档绘图
这里主要记博主自己练手的一个小例子。
项目效果如图所示:
主要功能包括:画直线、画多段线、画椭圆、画矩形;鼠标单击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<CPoint> m_vSelectPoints;
std::vector<CPoint> m_vLinePoints;
std::vector<CPoint> m_vPLPointsCell;
std::vector<std::vector<CPoint>> m_vPLPoints;
std::vector<CPoint> m_vEllipsePoints;
std::vector<CPoint> 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-单文档GDI动态绘图的全部内容,希望文章能够帮你解决日落MFC-单文档GDI动态绘图所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复