MFC中基于对话框利用CRectTracker实现多矩形绘制、选择、拉伸、移动和删除

橡皮筋类(CRectTracker)

     要想实现图形的拉伸功能,可以借用vs函数库中封装的橡皮筋类(CRectTracker),达到事半功倍的效果。

        首先,简要介绍哈CRectTracker这个类:

      Windows自带的画图软件中可以用虚线框选择图像的某个区域,之后便可以拖动、放大、缩小该区域,这是通过橡皮筋类(CRectTracker)来实现的,它将实现用线框选中一个区域,并可以拖动、放大、缩小该区域。

      简介:

       CRectTracker类允许一个项被显示,移动,以不同的方式改变大小。虽然CRectTracker类是设计来支持用户以图形化界面与OLE项交互的,但是它的使用不仅限于支持OLE的应用程序。它可以使用在任何需要用户界面的地方。 
   CRectTracker的边框可以是实线,也可以是点线。可给予项一种阴影式边框或用一种阴影样式覆盖项,用来指示项的不同状态。你可以在项的外界或内部放置八个调整大小把手。(有关八个调整大小把手的解释,参见GetHandleMask。)最后,一个CRectTracker允许你在调整项的大小时改变项的方向。 
  要使用CRectTracker,首先要构造一个CRectTracker对象,并指定用哪种显示状态来初始化。然后,应用程序就可以使用这个界面,提供给用户有关与CRectTracker对象相关联的OLE项当前状态的直观反馈了。 
  #include <afxext.h> 
  请参阅: 
  COleResizeBar, CRect, CRectTracker::GetHandleMask 
  CRectTracker类成员 
  数据成员

m_nHandleSize确定调整大小把手的尺寸
m_rect矩形的以像素表示的当前位置
m_sizeMin确定矩形宽度和高度的最小值
m_nStyle跟踪器的当前风格

  构造

CRectTracker构造一个CRectTracker对象

  操作

Draw显示矩形,并显示八个调整把手(调用时若要正常显示调整把手,不能只是在重绘函数中调用,还需要在程序当前位置调用一次)
GetTrueRect返回矩形的宽度和高度,包括改变大小句柄
HitTest返回与CRectTracker对象关联的光标的当前位置(返回值>=0:在矩形内,小于0:矩形外)
NormalizeHit规范化一个单击测试代码
SetCursor根据光标在矩形上方的位置来设置光标
Track支持用户操作矩形(会捕捉鼠标左键弹起消息,一直到鼠标左键弹起才会执行其下面的程序;双击鼠标左键,将会当做响应Track完毕,并执行一次左键按下一次,左键弹起一起)
TrackRubberBand支持用户“橡皮筋”似的拉伸选择(此函数主要用于拉取矩形,用于选择区域内的矩形区域)

 可重载

OnChangedRect当矩形被改变大小或被移动时,此函数被调用
GetHandleMask调用此函数来获得一个CRectTracker项的调整大小把手的掩码
AdjustRect当矩形被改变大小时此函数被调用
DrawTrackerRect当画一个CRectTracker对象的边框时此函数被调用

   ☆需要注意的是:CRectTracker类并不是用来画矩形区域的,而是用来选择区域的!!!如果要实现画区域边框,还得利用其它绘制函数~

下面是实现的源代码:

  1. 首先,在stdafx.h头文件中加入
    #define MAX_RECT_NUM 100     //允许画的最多的矩形个数
  2.  
class CtestTracker826Dlg : public CDialogEx
{
// 构造
public:
	CtestTracker826Dlg(CWnd* pParent = NULL);	// 标准构造函数
 
// 对话框数据
	enum { IDD = IDD_TESTTRACKER826_DIALOG };
 
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);	// DDX/DDV 支持
 
 
// 实现
protected:
	HICON m_hIcon;
	CRectTracker m_rctCurTracker;   //当前选中的矩形区域
	CRectTracker m_rctTracker[MAX_RECT_NUM]; //用于存储已画的矩形区域
	bool m_IsChose;  //标记是否被选中
	bool m_IsDraw;   //标记“绘制”按钮是否按下
	int m_rectNum;   //当前实际已经画的矩形的个数
	int m_rctChoseNum;//当前选中的矩形的编号
	int m_FlaMoveStep;//键盘方向键每响应一次的图像移动的像素单位上的步长
	int dirct;     //用于标记那个方向键按下。1:左,2:右,3:上,4:下,5:delete(删除)
	// 生成的消息映射函数
	virtual BOOL OnInitDialog();
	afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
	afx_msg void OnPaint();
	afx_msg HCURSOR OnQueryDragIcon();
	DECLARE_MESSAGE_MAP()
public:
	<span style="color:#ff6666;">afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
	afx_msg void OnBnClickedButton1();//“绘制”按钮的响应函数
//	afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags);
         	virtual BOOL PreTranslateMessage(MSG* pMsg);
	// 键盘消息时的移动方向
//	void ChangeRectPt(void);
	void ChangeRectPt(int ChangeDirct);
	afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
};

 

BOOL CtestTracker826Dlg::OnInitDialog()
{
	CDialogEx::OnInitDialog();
          …………        
	// TODO: 在此添加额外的初始化代码
	<span style="color:#ff6666;">m_rctCurTracker.m_rect.SetRect(0,0,0,0);//设置矩形区域大小
	m_rctCurTracker.m_nStyle=CRectTracker::dottedLine|CRectTracker::resizeInside;
	m_rctCurTracker.m_nHandleSize=6;
	for (int i=0;i<MAX_RECT_NUM;i++)
	{
		m_rctTracker[i].m_rect.SetRect(0,0,0,0);//设置矩形区域大小
		m_rctTracker[i].m_nStyle=CRectTracker::dottedLine|CRectTracker::resizeInside;
		m_rctTracker[i].m_nHandleSize=6;
	}
	
	m_IsChose=FALSE;//表示未选中
	m_IsDraw=false;
	m_rectNum=0;
	m_rctChoseNum=0;
	m_FlaMoveStep=2;
	dirct=0;
	return TRUE;  // 除非将焦点设置到控件,否则返回 TRUE
}

 

void CtestTracker826Dlg::OnPaint()
{
	CPaintDC dc(this); // 用于绘制的设备上下文
	if (IsIconic())
	{
            …………
	}
	else
	{
		CDialogEx::OnPaint();
		//if (m_IsChose)
		{
			if(m_IsChose)
				m_rctCurTracker.Draw(&dc);//若选择了该区域,则显示边框以及8个调整点
			CPen pen(PS_SOLID,1,RGB(100,255,200));
			dc.SelectObject(&pen);
 
			CBrush *pbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
			dc.SelectObject(pbrush);
			CRect rect;
			m_rctCurTracker.GetTrueRect(&rect);//得到矩形区域的大小
			dc.Rectangle(&rect);//画出矩形
			CSize rct_size;
			for (int i=0;i<MAX_RECT_NUM;i++)
			{
				m_rctTracker[i].GetTrueRect(&rect);//得到矩形区域的大小
				rct_size=m_rctTracker[i].m_rect.Size();
				
				if (rct_size.cx * rct_size.cy==0||i==m_rctChoseNum)
				{
					continue;
				}
				dc.Rectangle(&rect);//画出矩形
			}
			//CRect rect1;
			/*rect1.top=rect.top+3;
			rect1.bottom=rect.bottom-3;
			rect1.left=rect.left+3;
			rect1.right=rect.right-3;
			pbrush=CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
			dc.SelectObject(&brush);
			dc.Rectangle(&rect1);*/
			
		}
		
	}
}

 

void CtestTracker826Dlg::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	bool IsInRct=false;
	int i=0;
	do 
	{
		if (m_rctTracker[i].HitTest(point)<0)
		{
			IsInRct=false;
		}
		else
		{
			IsInRct=true;
			m_rctChoseNum=i;
			m_rctCurTracker=m_rctTracker[m_rctChoseNum];
			m_IsChose=true;
			break;
		}
		i++;
			
	} while (i<m_rectNum);
	if(!IsInRct)
	{
		CRectTracker tempRectTracker;
		CRect rect;
		tempRectTracker.TrackRubberBand(this,point);
		tempRectTracker.m_rect.NormalizeRect();
		if(rect.IntersectRect(tempRectTracker.m_rect,m_rctCurTracker.m_rect))
			m_IsChose=TRUE;
		else
		{
			m_IsChose=false;
			if (m_IsDraw)
			{
				//m_IsChose=FALSE;
				m_rctTracker[m_rectNum].m_rect=tempRectTracker.m_rect;
				m_rctCurTracker.m_rect=m_rctTracker[m_rectNum].m_rect;
				CClientDC dc(this);
				m_rctCurTracker.Draw(&dc);
                                        //注意!!在这里一定要调用绘制边框的程序,否则单凭onpaint中绘制,不能显示出来
</span>				m_rctChoseNum=m_rectNum;
				m_rectNum++;
				if (m_rectNum>=MAX_RECT_NUM)
				{
					m_rectNum=MAX_RECT_NUM;
					MessageBoxA(NULL,"已画矩形超过上限,不能再画矩形区域","警告",MB_OK);
				}
				m_IsChose=TRUE;
				m_IsDraw=false;
				
				Invalidate();
			}
			
		}
			
		
		Invalidate();
	}
	else
	{
		CClientDC dc(this);
		m_rctCurTracker.Draw(&dc);
		m_rctCurTracker.Track(this,point);
		m_rctCurTracker.m_rect.NormalizeRect();
		m_rctTracker[m_rctChoseNum]=m_rctCurTracker;
		m_IsChose=TRUE;
		
		Invalidate();
	}
	CDialogEx::OnLButtonDown(nFlags, point);
}

 

void CtestTracker826Dlg::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码]
	m_IsDraw=true;
}
BOOL CtestTracker826Dlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if(pWnd==this && m_rctCurTracker.SetCursor(this,nHitTest))
		return TRUE;
	return CDialogEx::OnSetCursor(pWnd, nHitTest, message);
}

 

BOOL CtestTracker826Dlg::PreTranslateMessage(MSG* pMsg)
{
	// TODO: 在此添加专用代码和/或调用基类
	
	if (pMsg->message==WM_KEYDOWN)
	{
		
		
		switch (pMsg->wParam)
		{
		case VK_LEFT:
			dirct=1;
			break;
		case VK_RIGHT:
			dirct=2;
			break;
		case VK_UP:
			dirct=3;
			break;
		case VK_DOWN:
			dirct=4;
			break;
		case VK_DELETE:
			dirct=5;
			break;
		default:
			dirct=0;
		}
	}
	
	ChangeRectPt(dirct);
	
	return CDialogEx::PreTranslateMessage(pMsg);
}

运行结果

  • 1
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值