如何基于MFC制作简易绘图软件

您所在的位置:网站首页 绘图软件操作 如何基于MFC制作简易绘图软件

如何基于MFC制作简易绘图软件

2024-03-19 03:46| 来源: 网络整理| 查看: 265

本文将讲解如何通过MFC制作一个简易的绘图软件

文章目录 一、构造软件的界面二、画出图形三、图形的保存与重绘四、程序下载

一、构造软件的界面

首先新建一个MFC的工程,进入之后按F5调试,可以看到现在的界面 在这里插入图片描述

停止调试,开始看我们的程序,进入资源视图–>myxxxxxx.rc–>Menu->IDR_MAINFRAME 新键入按钮“画图”及其子按钮“线段”,并修改其ID为ID_Line 在这里插入图片描述 进入资源视图–>myxxxxxx.rc–>toolbar->IDR_MAINFRAME_256 新键入图形按钮“线段”,并修改其ID为ID_Line 在这里插入图片描述 此时调试会发现“线段”这个按钮是灰的,所以我们需要对他添加命令 点击项目–>类向导–>选择ID_Line,记得类名那儿选择xxxxxxxview 在这里插入图片描述

然后点进xxxxxxxview会找到一个对应的函数,但内容为空,所以我们可以定义int型的标志type,在函数中写入type=1,表示点击“线段”按钮时type=1,可以作为之后导向画线段函数的标志。

void CMy1900402213View::OnLine() { type = 1; } void CMy1900402213View::OnSquare() { type = 2; } void CMy1900402213View::OnCircle() { type = 3; }

要制作绘出圆形矩形甚至画笔颜色以及形状都可以如法炮制 最终调试时的软件界面如下 在这里插入图片描述

二、画出图形 以画直线为例

首先我们建立一个CLine的类,里面要写一个放置起点和终点的函数,和最后画图的函数

**CLine.h** #pragma once class CLine { public: CLine(); void Set_start_point(CPoint p); void Set_end_point(CPoint p); private: CPoint Line_start_point; CPoint Line_end_point; public: void Draw(CDC* pDC); }; **CLine.cpp** #include "pch.h" #include "CLine.h" CLine::CLine() { } void CLine::Set_start_point(CPoint p) { Line_start_point = p; } void CLine::Set_end_point(CPoint p) { Line_end_point = p; } void CLine::Draw(CDC* pDC) { pDC->MoveTo(Line_start_point); pDC->LineTo(Line_end_point); }

然后在xxxxxxview文件中添加鼠标点击,鼠标移动,鼠标抬起,三个消息处理函数 在这里插入图片描述

然后可以在xxxxxxxxview.cpp找到对应的三个空的消息处理函数,我们需要填充他,以直线为例,我们可以在鼠标点击时设置起始点,鼠标移动时一直设置终点,然后从起始点到终点画出一条直线

void CMy1900402213View::OnLButtonDown(UINT nFlags, CPoint point) { switch (type) { case 1: { m_pline = new CLine; m_pline->Set_start_point(point); }break; } start = true; CView::OnLButtonDown(nFlags, point); } void CMy1900402213View::OnMouseMove(UINT nFlags, CPoint point) { if (start == true) { CDC* pDC = GetDC(); if (type == 1) { m_pline->Set_end_point(point); m_pline->Draw(pDC); } ReleaseDC(pDC); } } void CMy1900402213View::OnLButtonUp(UINT nFlags, CPoint point) { start=false; }

此时调试,画直线时会发现有重影,这是因为鼠标每次移动都新设立了一个终点,也就是每次鼠标的移动都会新画一条线,但只有最后一条线才是我们想要的,可之前画出的线也还留在画布上,这个时候我们需要在画线前用一支反色笔(使用其他颜色的时候,这个反色笔其实是背景色,但如果这条线如果是白色的话,反色笔的颜色将会是黑色)把上一条线覆盖掉,即画出a线,接着鼠标移动画出了b线的同时会用一支白色的笔把a线覆盖掉,最后画布上只剩下b这一条线。 在这里插入图片描述

void CMy1900402213View::OnMouseMove(UINT nFlags, CPoint point) { if (start == true) { CDC* pDC = GetDC(); if (type == 1) { pDC->SetROP2(R2_NOTXORPEN);//调用反色笔 m_pline->Draw(pDC); m_pline->Set_end_point(point); m_pline->Draw(pDC); } ReleaseDC(pDC); } }

那么问题又来了,在vs2019的环境下,画好a线时会出现一条从坐标原点到a线起始点的黑线,我推测在画第一条a线的时候会有一条默认从坐标原点到起始点的白线,然后在反色笔的影响下变成了黑色,画出a线时会有一条从原点到a线起始点的黑线。所以我们要做一个标志,判断下我们现在画的是第几条线,如果是第一条线,那我们就需要绕开反色笔涂抹那一段程序,如果不是第一条线,那么就不用绕开。 在这里插入图片描述

void CMy1900402213View::OnMouseMove(UINT nFlags, CPoint point) { if (start == true) { CDC* pDC = GetDC(); if (type == 1) { if(go) { pDC->SetROP2(R2_NOTXORPEN);//调用反色笔 m_pline->Draw(pDC); } else go=ture; m_pline->Set_end_point(point); m_pline->Draw(pDC); } ReleaseDC(pDC); } }

这样之后就可以正常的画出直线了 在这里插入图片描述 圆与矩形也可以用类似的流程来绘出,不过圆需要设置圆心点和计算半径,矩形则需要设置起始点和对角点。 当然如果想改变线的颜色和形状的话

CDC* pDC = GetDC(); CPen pen(PS_SOLID, 1, RGB(255, 0, 0));//PS_SOLID是实线,PS_DOT是虚线,RGB就是那个RGB CPen* pOldPen = (CPen*)pDC->SelectObject(&pen); ReleaseDC(pDC);//最后必须释放掉 三、图形的保存与重绘

大家可能已经发现通过第二部分画出的直线是无法保存的,也就是说将窗口最小化后再打开时画的的直线就不见了,所以我们需要画完每一条直线后将其保存,并且一直重新绘制它。 至于如何保存直线的数据,并且提取它的数据来绘制,这里就要用到链表了

**Clist.h** #pragma once #ifndef Clist_h #define Clist_h #include #include using namespace std; struct Node { int now_RGB;//储存画笔颜色 int now_line;//储存线型 int num; void* data; int now_type;//储存形状 Node* next; Node() { next = NULL; } }; class CSlist { public: CSlist(); Node* first; void InputFront(Node* Pelem);//在前面插入最新的一个节点 int Length()const;//判断链表长度 bool IsEmpty()const;//判断链表是否为空 void MakeEmpty();//将链表清空 Node* Locate(int i);//将第i个数据取出 int Input_behind_pos(Node* Pelem, int pos);//在第几个数值之后插入新节点 int Input_before_pos(Node* Pelem, int pos); void Delete(int pos);//删除 }; #endif **Clist.cpp** #include"CSlist.h" #include #include using namespace std; CSlist::CSlist() { first=NULL; }; void CSlist::InputFront(struct Node* Pelem) { if (Pelem == NULL) return; Pelem->next = first; first= Pelem; } int CSlist::Length()const { if (first == NULL) return 0; struct Node* n = first; int length = 1; while (n->next) { length++; n = n->next; } return length; } bool CSlist::IsEmpty()const { if (first == NULL) { return true ; } else { return false; } } void CSlist::MakeEmpty() { struct Node* d; while (first) { d = first; first = first -> next; delete d; } return; } struct Node* CSlist::Locate(int i) { int j=0; struct Node* L = first; if (i data =m_pline; m_line_list.InputFront(repaint); } break; case 2: { repaint->now_type = 2; repaint->data = m_psquare; m_line_list.InputFront(repaint); } break; case 3: { repaint->now_type = 3; repaint->data = m_pcircle; m_line_list.InputFront(repaint); }break; } } go = false; start = false; CView::OnLButtonUp(nFlags, point); }

这样之后你所画的所有图形都被存储在一条链表中,就像一栋公寓,每一个房间里都是一个图形,里面记录着他的形状和他的特殊点。

然后继续在xxxxxxview.cpp文件中寻找ondraw函数,在这个里面添加上重绘图形的程序, 重绘的原理就是,利用循环,把链表中每个图形的数据拿出来,再根据图形的不一样,使用不同的绘图程序绘制。 注意,因为矩形和圆心其实是个背景色的封闭图形,重绘时可能会因为重绘的顺序导致,把一些线条遮住,所以我重绘时采用了空心笔刷,这样他们就是透明的封闭图形了。

void CMy1900402213View::OnDraw(CDC* pDC) { CMy1900402213Doc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: 在此处为本机数据添加绘制代码 int i,j; j = m_line_list.Length(); if (m_line_list.IsEmpty() == false) { for(i=0;iSelectStockObject(NULL_BRUSH);//空心笔刷 Node* paint; paint=m_line_list.Locate(i); if (paint->now_type == 1) { ((CLine*)paint->data)->Draw(pDC); } if (paint->now_type == 2) { ((CQuare*)paint->data)->Draw(pDC); } if (paint->now_type == 3) { ((CCircle*)paint->data)->Draw(pDC); } ReleaseDC(pDC); } } }

最后就可以做到像我这样了 在这里插入图片描述

四、程序下载

有很多细小的地方很难讲述完毕,大家可以直接下载程序看看 基于MFC制作的简易绘图软件



【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3