【MFC】实现简单画板功能,包含画点、画线、矩形、棋盘,指定棋盘大小等功能。

一.实现基础绘画功能

(一)新建工程

1.首先新建一个 MFC应用程序(这里我使用的是VS2012版本),我这里设置名称为Draw。
mfc新建页面
2.在以下页面选择 单文档,点击 完成 ,完成创建。
在这里插入图片描述
3.直接点击 调试运行 ,就可以看到你的画板啦。
可惜的是现在即使你点击鼠标,它也无法显示出任何笔迹,所以接下来我们就先从画点开始吧!

(二)实现画点功能

1.在 视图 中找到 类视图,在 类视图 中找到 C(你的文件名)View 这个类,例如我的文件名为 Draw 故而我的是 CDrawView 是这个类(后面我们就叫做视图类)。接下来我们的操作就在这个类中啦~
在这里插入图片描述在这里插入图片描述
2.在电脑上如何画画呢?肯定是要借助鼠标的,所以需要我们添加两个 消息事件,来在我们 按下鼠标 和 抬起鼠标 的时候进行绘图。

  1. 右键点击 视图类-属性,点击闪电之后的按钮,出现以 VM_ 开头的,就是消息事件啦。选择如下图所示的 L开头的 LBUTTONDOWN,点击后面的小箭头,添加即可。
  2. 同样方法添加 LBUTTONUP 消息函数。
    在这里插入图片描述
    在这里插入图片描述
    3.添加存储起点和终点的变量

为了存储鼠标点击下去和放开时的点,以便于我们进行后续的画点、画线行为,我们需要存储这两个点~~~接下来我们来设置存储点的变量吧。

1.在 类视图 窗口中选择 视图类 点击进入,找一个**public:**写入 CPoint m_point1; CPoint m_point2;,CPoint 是可以存储点的类,m_point1和m_point2 是存储点的变量名,自己随意起名就可以。

public: CPoint m_point1;
		CPoint m_point2;

2.接着,我们通过 视图-解决方案资源管理 进入我们视图类的.cpp文件,找到OnLButtonDown()这个函数(也可以通过类视图下方的小框直接找到这个函数,点击进入),
写入代码:

m_point1=point;   //*在这里 OnLButtonDown()这个函数中point表示鼠标按下时获取到的点。

3.同理在OnLButtonUp()这个函数中写入代码:

m_point2=point;  //*在这里 OnLButtonUp()这个函数中point表示鼠标抬起时获取到的点。

4.好的,现在让我们来写入画点函数开始画点吧~

因为画点的话只需要给定一个点就可以,所以我们在OnButtonDown或者OnButtonUp()函数中任意选一个函数写入下方这段代码就可以啦~

CClientDC du(this);  //获得一个指向当前画板的句柄(可以理解为笔杆子)du为自定义变量。
du.SetPixel(point,RGB(255,0,0));  //画点函数,其中点的颜色通过RGB方式来指定。可以自行设定颜色。

因为点的像素很小,点击运行测试画板的时候一定记得注意仔细观察呀~~

(三)实现画直线功能

1.划线涉及两个点,起点和终点。而之前我们已经利用m_point1变量和m_point2变量存储了起点和终点。所以我们可以直接在OnButtonUp()函数中写入以下代码
注意:最好先注释掉画点函数,即上文中的du.SetPixel(point,RGB(255,0,0));

    m_point2=point;
	CClientDC du(this);  //获得一个指向当前画板的句柄(可以理解为笔杆子)du为自定义变量。
 //du.SetPixel(point,RGB(255,0,0));  //这句已经被注释掉
	du.MoveTo(m_point1);   //画笔先移动到了鼠标点击下去的点。这是线的起点。
	du.LineTo(m_point2);  //以鼠标释放的点为终点,画出一条直线。

好的,现在点击调试运行,按住鼠标拖动一下再释放鼠标,就可以看到你画的直线啦~

在这里插入图片描述

(四)实现画矩形功能

1.画矩形呢,也是需要两个点的,即左上角的点和右下角的点就可以完整的画出一个矩形。
这里呢我们先注释掉刚写入的画直线的这两句,然后写入以下代码:

    m_point2=point;
	CClientDC du(this);  //获得一个指向当前画板的句柄(可以理解为笔杆子)du为自定义变量。
 //du.SetPixel(point,RGB(255,0,0));  //这句已经被注释掉
	//du.MoveTo(m_point1);   //画笔先移动到了鼠标点击下去的点。这是线的起点。
	//du.LineTo(m_point2);  //以鼠标释放的点为终点,画出一条直线。
	du.Rectangle(m_point1.x,m_point1.y,m_point2.x,m_point2.y);//这里变量后的.x表示点的x轴坐标, .y表示点的y轴坐标。

当然这里也可以直接调用一个函数,一次性传入这四个变量,代码如下:

    m_point2=point;
	CClientDC du(this);  //获得一个指向当前画板的句柄(可以理解为笔杆子)du为自定义变量。
 //du.SetPixel(point,RGB(255,0,0));  //这句已经被注释掉
	//du.MoveTo(m_point1);   //画笔先移动到了鼠标点击下去的点。这是线的起点。
	//du.LineTo(m_point2);  //以鼠标释放的点为终点,画出一条直线。
	du.Rectangle(CRect(m_point1,m_point2));//和上述代码效果是一样的。

运行并点击拖动鼠标,铛啦~效果就出现啦

在这里插入图片描述

2.接下来我们来画一个实心矩形。这里需要用到画刷工具来为矩形填充颜色。
在画矩形那一句代码之前添加如下代码:

 Brush brush0(RGB(0,0,255));      //新建一个画刷,利用RGB设置颜色,这里是蓝色。
  du.SelectObject(&brush0);		//选入画刷,表示使用这个画刷。

运行并点击拖动鼠标,效果就实现啦。
在这里插入图片描述

(五)实现画棋盘功能

1.画棋盘呢分为两步:画格子,填充格子。首先我们来画格子。
在这里我的棋盘是八行八列,通过画线函数来实现。在此之前注释掉画矩形的那两句代码(选入画刷代码,画矩形代码)。将以下代码写入OnLButtonUp() 函数中去。

    int Ox=200;			//棋盘左上角的x轴起点
    int Oy=100;      //棋盘左上角的y轴起点
    int numx=9;		//直线列数
    int numy=9;		//直线行数
 int bulk=50;		//棋盘每个格子大小,设置变量是为了后续的交互式改变大小
 for(int i=0;i<numx;i++)//画列线
    {
        du.MoveTo(Ox+bulk*i,Oy);	
        du.LineTo(Ox+bulk*i,bulk*8+Oy);
    }
    for(int j=0;j<numy;j++)//画行线
    {
        du.MoveTo(Ox,Oy+bulk*j);
        du.LineTo(Ox+bulk*8,Oy+bulk*j);
    }
 CString str;
 for(int i=8;i>0;i--)
 {
  str.Format(_T("%d"),i);
  du.TextOut(Ox-30,bulk*8+100-bulk/2-(bulk*(i-1)),str);
 }
 char b[]={'A','B','C','D','E','F','G','H'};
 for(int j=1;j<9;j++)
 {
 str.Format(_T("%c"),b[j-1]);
  du.TextOut(Ox+bulk/2+bulk*(j-1),Oy-30,str);
 } 

2.好的,现在我们已经有了基础的棋盘格子,现在我们就来为棋盘填充颜色,同样用到画刷工具。

这里需要取消 选入画刷的那句代码的注释。然后在上方代码之后添加以下代码即可:

  for(int n=0;n<8;n=n+1)
   {
    
      for(int m=0;m<8;m=m+2)
      {
      CRect rc(Ox+bulk*m,Oy+n*bulk,Ox+bulk*m+bulk,Oy+n*bulk+bulk);      //分别是起点的x轴坐标,y轴坐标终点的x轴坐标,y轴坐标。
	  if(n%2==0)
	{
		du.FillRect(rc,&brush0);							//表示填充颜色。rc表示填充的区域。brush0表示填充区域所用的画刷。
	}
      }
   }

    for(int n=1;n<9;n=n+1)
   {
    
      for(int m=1;m<9;m=m+2)
      {
      
	  if(n%2!=0)
	{
		CRect rc(Ox+bulk*m,Oy+n*bulk,Ox+bulk*m+bulk,Oy+n*bulk+bulk);      //同上方。
		du.FillRect(rc,&brush0);
	}
      
      }
   }

好的,恭喜你,棋盘成型啦。效果如下:

在这里插入图片描述
偷了个懒,这里我只是填充了一半的格子。白色部分都是透明的。可以自己按逻辑尝试呀。

二、基础交互式示例

(一)、交互式指定绘画方式

我们注意到在在画板周围有菜单栏。所以我们接下来就利用菜单栏来进行绘画方式的选择。
在这里插入图片描述
这里我已经插入了一个绘画菜单~以下是过程。
1.找到资源视图,同理:视图-资源视图(没有的话,在视图-其他中找找。)

依次进入 menu 菜单,添加我们所用菜单。1.为我们自设的文件名。2.为Menu菜单。3.为我们所要找的菜单。如下。
在这里插入图片描述
在这里插入图片描述
2.在右边中找到划红线的部分,然后直接在其中输入控制绘画形式的菜单名:我在这里设置为 绘画 ,之后点击 绘画,依次输入 点、直线、矩形、棋盘、设置,效果如上。

测试运行就会发现我们所设置的菜单已经存在了,但均为灰色,这里我们想要实现功能是点击它,然后响应相应的事件。所以接下来我们为它添加响应事件。

3.依次右键点击我们在绘画中添加的菜单,例如”点“,点击它的属性,更改ID为容易辨识的,例如我的是:ID_Point。
在这里插入图片描述
依次为 直线: ID_Line 矩形:ID_Square 棋盘:ID_Chess 设置:ID_Setting(设置这个模块是为了后续的棋盘交互式的实现),当然,这里你也可以自己设置自己喜欢的名称。

4.现在右击 绘画 中的菜单,选择 添加事件处理程序 ,基类选择 视图类 例如我的则是 CDrawView,类型选择 COMAND ,添加编辑就可以了。

这里是以“点”为例,,大家依次添加消息处理程序即可。
在这里插入图片描述
5.交互式选择有两种方式。你可以选择直接在相应的事件处理程序中填入相应的代码。也可以选择设置一个全局变量和switch相结合的方式来进行交互式选择。

直接在相应消息函数中添加代码的交互方式,我们在这里不再赘述。下面我们来介绍第二种交互方式。

(1)首先,我们先设置一个全局变量,在我们 类视图-视图类的头文件中添加一个int 类型变量(设置为public 和private 均可,这里我设置为public)来告知我们用户的选择。

添加代码如下:

  int m_choose;		//我设置变量为 m_chosse;

(2)之后在返回视图类的 .cpp 中(寻找方法在上文),依次在“点”、“直线”、“矩形”、“棋盘”消息函数中给m_choose设置一个不同的值。(这里暂时忽略“Onseting()函数”)

示例如下:

  void CDrawView::OnPoint()
{
	// TODO: 在此添加命令处理程序代码
	m_choose=1;

}


void CDrawView::OnLine()
{
	// TODO: 在此添加命令处理程序代码
	m_choose=2;
}


void CDrawView::OnSquare()
{
	// TODO: 在此添加命令处理程序代码
	m_choose=3;
}


void CDrawView::OnChess()
{
	// TODO: 在此添加命令处理程序代码
	m_choose=4;
}


void CDrawView::OnSetting()
{
	// TODO: 在此添加命令处理程序代码
	
}

(3)给变量一个初始化:我们找到视图类的.cpp的构造函数。写入默认选定的选项。

例如我默认画直线故而初始化变量值为2。(因为点不明显)

在这里插入图片描述
**(4)在OnButtonUp() 写入以下代码:

  m_point2=point;
	CClientDC du(this);  //获得一个指向当前画板的句柄,du为自定义变量。
  int Ox=200;			//棋盘左上角的x轴起点
     int Oy=100;      //棋盘左上角的y轴起点
     int numx=9;		//直线列数
     int numy=9;		//直线行数
  int bulk=50;		//棋盘每个格子大小
  CBrush brush0(RGB(0,0,255));
  du.SelectObject(&brush0);
	
	switch (m_choose)
	{
	case 1:
		du.SetPixel(point,RGB(255,0,0));
		break;
	case 2:
		du.MoveTo(m_point1);
	du.LineTo(m_point2);break;
	case 3:
		 du.Rectangle(CRect(m_point1,m_point2));break;
	case 4:
		for(int i=0;i<numx;i++)//画列线
     {
         du.MoveTo(Ox+bulk*i,Oy);	
         du.LineTo(Ox+bulk*i,bulk*8+Oy);
     }
     for(int j=0;j<numy;j++)//画行线
     {
         du.MoveTo(Ox,Oy+bulk*j);
         du.LineTo(Ox+bulk*8,Oy+bulk*j);
     }
  CString str;
  for(int i=8;i>0;i--)
  {
   str.Format(_T("%d"),i);				//将数字转为CString类型
   du.TextOut(Ox-30,bulk*8+100-bulk/2-(bulk*(i-1)),str);     //绘制数字
  }
  char b[]={'A','B','C','D','E','F','G','H'};        //通过数组存储要绘制的字母
  for(int j=1;j<9;j++)
  {
  str.Format(_T("%c"),b[j-1]);				//将char类型字母改为CString
   du.TextOut(Ox+bulk/2+bulk*(j-1),Oy-30,str);  //输出字母
  } 
  for(int n=0;n<8;n=n+1)
   {
    
      for(int m=0;m<8;m=m+2)
      {
      CRect rc(Ox+bulk*m,Oy+n*bulk,Ox+bulk*m+bulk,Oy+n*bulk+bulk);
	  if(n%2==0)
	{
		du.FillRect(rc,&brush0);
	}
      }
   }

    for(int n=1;n<9;n=n+1)
   {
    
      for(int m=1;m<9;m=m+2)
      {
      
	  if(n%2!=0)
	{
		CRect rc(Ox+bulk*m,Oy+n*bulk,Ox+bulk*m+bulk,Oy+n*bulk+bulk);
		du.FillRect(rc,&brush0);
	}
      
      }
   }
   break;
	}

点击就可实现不同的功能。
PS:期间有不可更改ID等情况,建议关闭后重新打开。
至此,我们基本功能已完成,但仍旧存在一些问题,我们后续进行完善。

(二)、交互式指定棋盘大小

首先确定思路:我这里思路是弹出对话框,利用对话框输入棋盘每个格子大小,从而间接改变整个棋盘大小。

1.首先我们来新建一个对话框,用于输入棋盘大小。

1).首先进入 资源视图,找到 Dialog,右键单击,选中 插入Dialog(E) ,对话框就新建好了。
在这里插入图片描述
2).选中菜单栏的 视图-工具箱,打开如下页面,依次选中以下标红的 编辑文本框 和 静态文本框。进行布局。(直接点击对话框中控件输入文字就可以改变控件显示的文本)
在这里插入图片描述
我的布局如下:
在这里插入图片描述右键单击控件,属性,更改ID(这里我更改为IDC_Size):
在这里插入图片描述
3).左键双击对话框,弹出添加类窗口,添加类如下(类名自定):
在这里插入图片描述
4).完成后,回到对话框页面,右键点击 编辑框,添加变量,用于接收我们输入的数据。类型为int。如下(变量名自定):
在这里插入图片描述
完成后,进入类视图,这时就已经可以看到我们新加的类已经在类视图的最底端。点击进入可以看到我们新加的变量也在其中。完成对话框的创建!

2.现在我们将我们进行 点击设置,弹出对话框的功能的实现。

1).首先我们先在视图类的.cpp文件的最上方添加如下代码:

  #include "Setting.h"  		//这里是你新添加的类名的头文件(类名.h),表示引用这个文件的内容。

2).找到我们上文添加的设置菜单的响应函数 OnSetting() ,并写入以下代码:

  Setting dlg;				//对话框类的一个变量
	dlg.DoModal();		//弹出一个非模态对话框

运行,依次点击绘画-设置效果如下:
在这里插入图片描述
现在默认数值为0;
3).为了接收用户输入的变量来在视图类中随意调用,我们需要再在视图类的头文件中再添加一个int型变量。我设置为public类型。

  public:
  int m_SSize;          //接收用户输入的尺寸。

同样的在构造函数中初始化m_SSize(构造函数位置在上文提到过);

m_SSize=50;     //因为我们现在棋盘大小设置的是50,故而现在先设置为50

好的,接下来我们开始进行数据的交互:
注释掉我们刚在OnSetting()输入的第二行代码,写入以下代码:

    Setting dlg;
    //dlg.DoModal();
	dlg.m_Size=m_SSize;          //将棋盘现在的大小传给对话框,这时对话框中默认值就为50了
if(IDOK==dlg.DoModal())          //只有按 确认键时,数据才被传入m_SSize
	{ 
		UpdateData(TRUE);						//用于刷新数据,有些版本不需这两句也可达到目的
		m_SSize=dlg.m_Size;						//将对话框的数据传入视图类
		UpdateData(FALSE);
	}

现在运行效果如下:
在这里插入图片描述
3.更改棋盘大小实现。
我们已经可以用m_SSize接收到用户输入的数据。现在只需将OnButtonUp()函数中的绘制棋盘函数中的这句更改即可:

int bulk=m_SSize;		//棋盘每个格子大小,50改为了m_SSize

现在即可实现更改棋盘大小,但是存在问题:前面绘制的棋盘并未消失?

4.刷新棋盘的实现。
持续更新,整理真的好费时间QAQ

  • 32
    点赞
  • 170
    收藏
    觉得还不错? 一键收藏
  • 11
    评论
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值