关于MFC如何用鼠标事件实现矩形绘制,边框的拉伸。

1.首先新建一个基于对话框的MFC程序

在这里插入图片描述
2.点击Class View Dlg类鼠标右键的属性,重写消息里面的鼠标移动、鼠标右键按下、抬起,三个消息。
在这里插入图片描述
我们在Dialog中添加一个静态文本框,然后在鼠标移动事件函数中添加以下代码就会发现随着鼠标移动,界面上就会显示当前鼠标的坐标信息。

void CMFCDrawLineAndMouseMoveDlg::OnMouseMove(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default
	CString str;
	str.Format(_T("x=%d  y=%d"),point.x,point.y);
	GetDlgItem(IDC_STATIC)->SetWindowTextW(str);
}

当鼠标在界面上移动时,坐标也会随之改变
3.然后我们就可以利用上面的原理实现对框的移动和拉伸,首先我们需要绘制出一个矩形方框。

void CMFCDrawLineAndMouseMoveDlg::myDraw()//绘制方框函数
{
	CPen *pOldPen = m_pDc->SelectObject(&/*pen*/m_objPen);
	int nOldDrawMode = m_pDc->SetROP2(R2_NOTXORPEN);
	m_pDc->SelectStockObject(NULL_BRUSH);
	m_pDc->MoveTo(m_pairCaliper.startPoint.x ,m_pairCaliper.startPoint.y);
	m_pDc->LineTo( m_pairCaliper.endPoint.x ,m_pairCaliper.startPoint.y);
	m_pDc->MoveTo( m_pairCaliper.startPoint.x ,m_pairCaliper.endPoint.y);
	m_pDc->LineTo(m_pairCaliper.endPoint.x,m_pairCaliper.endPoint.y);

	m_pDc->MoveTo(m_pairCaliper.endPoint.x,m_pairCaliper.startPoint.y );
	m_pDc->LineTo(m_pairCaliper.endPoint.x,m_pairCaliper.endPoint.y );

	m_pDc->MoveTo(m_pairCaliper.startPoint.x,m_pairCaliper.startPoint.y );
	m_pDc->LineTo(m_pairCaliper.startPoint.x,m_pairCaliper.endPoint.y );
	m_pDc->SelectObject(pOldPen);
}

m_objPen,m_pairCaliper,m_pDc在.h函数中声明:

PointPair m_pairCaliper;//
CDC *m_pDc;
CPoint m_pStart;
struct PointPair
{
	CPoint startPoint;
	CPoint endPoint;
};

在构造函数中初始化

	m_pairCaliper.startPoint.x = 100;
	m_pairCaliper.startPoint.y = 100;
	m_pairCaliper.endPoint.x = 200;
	m_pairCaliper.endPoint.y = 200;
	m_objPen.CreatePen(PS_SOLID, 1, RGB(250,0,0));//红色的绘图笔

我们在确定按钮中加入myDraw()函数点击就会发现在界面上会生成一个红色的方框。

void CMFCDrawLineAndMouseMoveDlg::OnBnClickedOk()
{
	// TODO: Add your control notification handler code here
	myDraw();
}

在这里插入图片描述
但是这时我们只是生成了这个方框,所以接下来我们应该要实现鼠标拉伸边和移动整个方框。主要用两个函数实现。MoveBorder(),MoveRect()

void CMFCDrawLineAndMouseMoveDlg::OnMouseMove(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default
	CString str;
	str.Format(_T("x=%d  y=%d"),point.x,point.y);
	GetDlgItem(IDC_STATIC)->SetWindowTextW(str);
	if (bMoveBorder == true)//移动框的一条边;
	{
		MoveBorder(point);
	}
	else if (bMoveRect == true)//移动整个框
	{
		SetCursor(LoadCursor(NULL, IDC_SIZEALL));//设置鼠标形状为十字箭头型
		MoveRect(point);
	}
	CDialogEx::OnMouseMove(nFlags, point);
}

由于代码过长,这里就只放实现拉伸左右边框的代码,具体原理就是如果拉伸右边框,那么做边框就不需要动,然后重新根据获得的鼠标坐标绘制右、上、下、三条边。首先将原本的三条边按原来的位置重新画一遍(在原本的位置重新画一遍该线会消失)。然后将鼠标的值赋给保存变量的值,再画一遍,也就是鼠标拉伸后所在的位置。MoveTo LineTo和相关绘制函数不懂的可以自行CSDN。

void CMFCDrawLineAndMouseMoveDlg::MoveBorder(CPoint &point)
{
	CPen *pOldPen = m_pDc->SelectObject(&/*pen*/m_objPen);
	int nOldDrawMode = m_pDc->SetROP2(R2_NOTXORPEN);
	m_pDc->SelectStockObject(NULL_BRUSH);
	if (bLeftBorder == true)//如果鼠标按在左边框
	{
		SetCursor(LoadCursor(NULL, IDC_SIZEWE));//将鼠标形状变成左右箭头
		m_pDc->MoveTo(m_pairCaliper.startPoint.x ,m_pairCaliper.startPoint.y);
		m_pDc->LineTo( m_pairCaliper.endPoint.x ,m_pairCaliper.startPoint.y);
		m_pDc->MoveTo( m_pairCaliper.startPoint.x ,m_pairCaliper.endPoint.y);
		m_pDc->LineTo(m_pairCaliper.endPoint.x,m_pairCaliper.endPoint.y);
		m_pDc->MoveTo(m_pairCaliper.startPoint.x,m_pairCaliper.startPoint.y );
		m_pDc->LineTo(m_pairCaliper.startPoint.x,m_pairCaliper.endPoint.y );
		if (point.x > m_pairCaliper.endPoint.x - 5)//防止拉伸时左边框拉伸到右边,设置距离最小值
		{
			m_pairCaliper.startPoint.x = m_pairCaliper.endPoint.x - 5;
		}
		else
		{
			m_pairCaliper.startPoint.x = point.x;
		}
		m_pDc->MoveTo(m_pairCaliper.startPoint.x ,m_pairCaliper.startPoint.y);
		m_pDc->LineTo( m_pairCaliper.endPoint.x ,m_pairCaliper.startPoint.y);
		m_pDc->MoveTo( m_pairCaliper.startPoint.x ,m_pairCaliper.endPoint.y);
		m_pDc->LineTo(m_pairCaliper.endPoint.x,m_pairCaliper.endPoint.y);
		m_pDc->MoveTo(m_pairCaliper.startPoint.x,m_pairCaliper.startPoint.y );
		m_pDc->LineTo(m_pairCaliper.startPoint.x,m_pairCaliper.endPoint.y );
	}
	else if (bRightBorder == true)//如果鼠标按在右边框
	{
		SetCursor(LoadCursor(NULL, IDC_SIZEWE));
		m_pDc->MoveTo(m_pairCaliper.startPoint.x ,m_pairCaliper.startPoint.y);
		m_pDc->LineTo( m_pairCaliper.endPoint.x ,m_pairCaliper.startPoint.y);
		m_pDc->MoveTo( m_pairCaliper.startPoint.x ,m_pairCaliper.endPoint.y);
		m_pDc->LineTo(m_pairCaliper.endPoint.x,m_pairCaliper.endPoint.y);

		m_pDc->MoveTo(m_pairCaliper.endPoint.x,m_pairCaliper.startPoint.y );
		m_pDc->LineTo(m_pairCaliper.endPoint.x,m_pairCaliper.endPoint.y );

		m_pDc->MoveTo(m_pairCaliper.startPoint.x,m_pairCaliper.startPoint.y );
		m_pDc->LineTo(m_pairCaliper.startPoint.x,m_pairCaliper.endPoint.y );
		if (point.x < m_pairCaliper.startPoint.x + 5)
		{
			m_pairCaliper.endPoint.x = m_pairCaliper.startPoint.x + 5;
		}
		else
		{
			m_pairCaliper.endPoint.x = point.x;
		}
		m_pDc->MoveTo(m_pairCaliper.startPoint.x ,m_pairCaliper.startPoint.y);
		m_pDc->LineTo( m_pairCaliper.endPoint.x ,m_pairCaliper.startPoint.y);
		m_pDc->MoveTo( m_pairCaliper.startPoint.x ,m_pairCaliper.endPoint.y);
		m_pDc->LineTo(m_pairCaliper.endPoint.x,m_pairCaliper.endPoint.y);
		m_pDc->MoveTo(m_pairCaliper.endPoint.x,m_pairCaliper.startPoint.y );
		m_pDc->LineTo(m_pairCaliper.endPoint.x,m_pairCaliper.endPoint.y );
		m_pDc->MoveTo(m_pairCaliper.startPoint.x,m_pairCaliper.startPoint.y );
		m_pDc->LineTo(m_pairCaliper.startPoint.x,m_pairCaliper.endPoint.y );
	}
}

4.这个时候我们发现需要获得鼠标左键按下是到底是在哪条边框,或者是在方框内部从而判断到底是移动方框还是拉伸边。
在.h文件中声明下面的布尔类型,然后再构造函数中全都初始化为false

	bool bMoveBorder;//ture是拉伸边
	bool bMoveRect;//true是移动方框
	bool bLeftButtonDown;//判断鼠标左键是否按下
	bool bTopBorder;//上边框
	bool bBottomBorder;//下边框
	bool bLeftBorder;//左边框
	bool bRightBorder;//右边框
	CPoint m_classOriginPoint;
	bMoveBorder = false;
	bMoveRect = false;
	bLeftButtonDown = false;
	bTopBorder = false;
	bBottomBorder = false;
	bLeftBorder = false;
	bRightBorder = false;

鼠标左键事件中加入以下代码判断鼠标按下时是按在哪条边上或者是方框内部

void CMFCDrawLineAndMouseMoveDlg::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default
	CRect LeftRect = GetLeftRect(m_pairCaliper);
	CRect TopRect = GetTopRect(m_pairCaliper);
	CRect RightRect = GetRightRect(m_pairCaliper);
	CRect BottomRect = GetBottomRect(m_pairCaliper);
	CRect rect(/*m_classStartPoint*/m_pairCaliper.startPoint, /*m_classEndPoint*/m_pairCaliper.endPoint);
	bLeftButtonDown = true;
	if(LeftRect.PtInRect(point))//按在左边框上
	{
		SetCursor(LoadCursor(NULL, IDC_SIZEWE));//鼠标形状变成左右箭头
		bMoveBorder = true;
		bLeftBorder = true;
	}
	else if(TopRect.PtInRect(point))//按在上边框上
	{
		SetCursor(LoadCursor(NULL, IDC_SIZENS));//鼠标形状变成上下箭头
		bMoveBorder = true;
		bTopBorder = true;
	}
	else if(RightRect.PtInRect(point))//按在右边框上
	{
		SetCursor(LoadCursor(NULL, IDC_SIZEWE));
		bMoveBorder = true;
		bRightBorder = true;
	}
	else if(BottomRect.PtInRect(point))//按在下边框上
	{
		SetCursor(LoadCursor(NULL, IDC_SIZENS));
		bMoveBorder = true;
		bBottomBorder = true;
	}
	else if(rect.PtInRect(point))//按在方框内部,移动方框
	{
		// 移动测量框
		bMoveRect = true;
		SetCursor(LoadCursor(NULL, IDC_SIZEALL));
	}
	m_classOriginPoint.x = point.x;//CPoint类型,保存按下时鼠标的位置,在移动方框时需要用到
	m_classOriginPoint.y = point.y;
	CDialogEx::OnLButtonDown(nFlags, point);
}

GetLeftRect(),GetTopRect(),GetTopRect(),GetBottomRect()函数如下

CRect CMFCDrawLineAndMouseMoveDlg::GetLeftRect( const PointPair &pointPair ) const
{
	CRect LeatRect(pointPair.startPoint.x - 3, pointPair.startPoint.y, pointPair.startPoint.x + 3, pointPair.endPoint.y);
	return LeatRect;
}

CRect CMFCDrawLineAndMouseMoveDlg::GetTopRect( const PointPair &pointPair ) const
{
	CRect TopRect(pointPair.startPoint.x, pointPair.startPoint.y - 3, pointPair.endPoint.x, pointPair.startPoint.y + 3);
	return TopRect;
}

CRect CMFCDrawLineAndMouseMoveDlg::GetRightRect( const PointPair &pointPair ) const
{
	CRect RightRect(pointPair.endPoint.x - 3, pointPair.startPoint.y, pointPair.endPoint.x + 3, pointPair.endPoint.y);
	return RightRect;
}

CRect CMFCDrawLineAndMouseMoveDlg::GetBottomRect( const PointPair &pointPair ) const
{
	CRect BottomRect(pointPair.startPoint.x, pointPair.endPoint.y - 3, pointPair.endPoint.x, pointPair.endPoint.y + 3);
	return BottomRect;
}

在鼠标左键抬起时我们需要将相关的bool类型重新变成false

void CMFCDrawLineAndMouseMoveDlg::OnLButtonUp(UINT nFlags, CPoint point)
{
	// TODO: Add your message handler code here and/or call default
	bLeftButtonDown = false;
	bTopBorder = false;
	bBottomBorder = false;
	bLeftBorder = false;
	bRightBorder = false;
	bMoveRect = false;
	CDialogEx::OnLButtonUp(nFlags, point);
}

移动方框的函数MoveRect()的实现,具体也就是先将原本的方框画一遍删除,然后获得新的坐标重新画一遍方框就是移动后的方框。

void CMFCDrawLineAndMouseMoveDlg::MoveRect(CPoint &point)
{
	if(m_pDc)
	{
		CString strMeasureResult;
		int nMoveWidth = point.x - m_classOriginPoint.x;
		int nMoveHeight = point.y - m_classOriginPoint.y;
		myDraw();//将原来的方框画一遍删除
		m_pairCaliper.startPoint.x += nMoveWidth;
		m_pairCaliper.startPoint.y += nMoveHeight;
		m_pairCaliper.endPoint.x += nMoveWidth;
		m_pairCaliper.endPoint.y += nMoveHeight;
		m_classOriginPoint = point;
		myDraw();
		//pen.DeleteObject();
	}
}

由于作者是20届刚刚毕业的新手,在写作和代码方面许多地方都有不好的地方,如果大家有不明白的地方可以讨论,有指点的地方我也一定会修正。本文更多的像是写给自己的一个笔记,如果能帮到大家我也十分开心。-。-

  • 7
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
MFC实现鼠标左键选中矩形并移动,可以按照以下步骤实现: 1. 定义一个CRect对象,用于表示选中的矩形。 2. 在鼠标左键按下的消息响应函数中,根据鼠标的位置确定选中的矩形,并将其保存到CRect对象中。 3. 在鼠标移动的消息响应函数中,判断是否已经选中了矩形。如果已经选中了矩形,则根据鼠标移动的偏移量,更新选中矩形的位置。 4. 在鼠标左键抬起的消息响应函数中,清除选中矩形的标记。 下面是一个示例代码: ``` CRect selectedRect; // 保存选中的矩形 // 鼠标左键按下 void CMyView::OnLButtonDown(UINT nFlags, CPoint point) { // 判断是否选中了矩形 if (m_rect.PtInRect(point)) { selectedRect = m_rect; // 保存选中的矩形 } } // 鼠标移动 void CMyView::OnMouseMove(UINT nFlags, CPoint point) { // 判断是否已经选中了矩形 if (!selectedRect.IsRectEmpty()) { // 计算鼠标移动的偏移量 int offsetX = point.x - m_lastMousePos.x; int offsetY = point.y - m_lastMousePos.y; // 更新选中矩形的位置 selectedRect.OffsetRect(offsetX, offsetY); // 重绘图形 Invalidate(); } // 保存上一次鼠标的位置 m_lastMousePos = point; } // 鼠标左键抬起 void CMyView::OnLButtonUp(UINT nFlags, CPoint point) { selectedRect.SetRectEmpty(); // 清除选中矩形的标记 } ``` 需要注意的是,在鼠标移动的消息响应函数中,需要调用Invalidate函数来触发重绘操作。同时,为了计算鼠标移动的偏移量,需要保存上一次鼠标的位置。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值