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 支持用户“橡皮筋”似的拉伸选择(此函数主要用于拉取矩形,用于选择区域内的矩形区域)


  可重载

AdjustRect 当矩形被改变大小时此函数被调用
DrawTrackerRect 当画一个CRectTracker对象的边框时此函数被调用
OnChangedRect 当矩形被改变大小或被移动时,此函数被调用
GetHandleMask 调用此函数来获得一个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);
    };
    
  3. 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
    }
    
    
    
  4. 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);*/
    			
    		}
    		
    	}
    }
    
    
    
  5. 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);
    }
    
    
    
    
    
  6. void CtestTracker826Dlg::OnBnClickedButton1()
    {
    	// TODO: 在此添加控件通知处理程序代码]
    	m_IsDraw=true;
    }
    
    
    
    
    
  7. 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);
    }
    
    
    
    
    
  8. 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);
    }
    
    
    
    
    
  9. void CtestTracker826Dlg::ChangeRectPt(int ChangeDirct)
    {
    	CRect rct;
    	rct=m_rctCurTracker.m_rect;
    	switch (ChangeDirct)
    	{
    	case 1://左移
    		rct.TopLeft().x-=m_FlaMoveStep;
    		rct.BottomRight().x-=m_FlaMoveStep;
    		break;
    	case 2://右移
    		rct.TopLeft().x+=m_FlaMoveStep;
    		rct.BottomRight().x+=m_FlaMoveStep;
    		break;
    	case 3://下移
    		rct.TopLeft().y-=m_FlaMoveStep;
    		rct.BottomRight().y-=m_FlaMoveStep;
    		break;
    	case 4://上移
    		rct.TopLeft().y+=m_FlaMoveStep;
    		rct.BottomRight().y+=m_FlaMoveStep;
    		break;
    	case 5://删除
    		m_rctCurTracker.m_rect.SetRect(0,0,0,0);
    		m_rctTracker[m_rctChoseNum]=m_rctCurTracker;
    		dirct=0;
    		Invalidate();
    		return;
    	}
    	m_rctCurTracker.m_rect.SetRect(rct.TopLeft(),rct.BottomRight());
    	m_rctTracker[m_rctChoseNum]=m_rctCurTracker;
    	if (ChangeDirct!=0)
    	{
    		Invalidate();
    	}
    	dirct=0;
    	
    }
    
  10. 运行结果


    
    
    
    


©️2020 CSDN 皮肤主题: 大白 设计师: CSDN官方博客 返回首页
实付0元
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值