使用CRectTracker类进行对象动态定位(一)

来源:互联网 发布:软件定制开发协议 编辑:程序博客网 时间:2024/06/07 09:56
内容提要
使用VC,VB,Delphi等可视化工具进行程序设计的时候用的最多的可能就是控件的拾取,拖动以及动态定位了。例如我们可以在VC中用鼠标一次拾取数个控件,然后通过鼠标或者通过左右上下方向键进行控件的微移,从而使控件移到合适的位置,这种技术就是对象动态定位。动态定位也是交互式程序设计中最基本的操作之一。在VC中我们可以通过CRectTracker类来实现这些操作。
文章正文
一 关于中的OLE在内的应用程序。首先我们了解一下类的成员变量和成员函数
1. CRectTracker类的成员变量:
m_nHandleSize:对象的调整句柄的数目,默认情况下为8个
m_rect:对象矩形目前所占大小的位置
m_sizeMin:对象所占的矩形的最小宽度和最小高度
m_nStyle:目前对象边框和调整句柄的类型
2.CRectTracker类的成员函数
Draw(CDC* pDC):通过调用这个函数来画对象边框和调整句柄的类型。对象边框和调整句柄的具体类型由成员变量m_nStyle决定,一共有以下几种形式:
CRectTracker::solidLine 外部边界使用实线形式外部边界使用点虚线形式
CRectTracker::hatchedBorder 外部边界使用带阴影的形式调整句柄处于对象内部区域
CRectTracker::resizeOutside 调整句柄处于对象外部区域
CRectTracker::hatchInside 内部所有区域使用带阴影的形式
CRectTracker::solidLine和CRectTracker::resizeOutside不能同时共存
Track(CWnd* pWnd,CPoint point,BOOL bAllowInvert=FALSE,CWnd* pWndClipTo=NULL)
这个函数和下面的TrackRubberBand函数是整个CRectTracker类中最重要的函数,通常在消息,如果鼠标指针落在矩形的边框上,用户就可以拖动以调整矩形的大小;如果鼠标落在了矩形的内部,则用户可以拖动鼠标移动矩形。当ESC键按下时候,函数返回FALSE,函数没有起作用, 否则松开鼠标时候,返回TRUE;

那么鼠标移动时候将会产生橡皮条,这个””GetTrueRect(LPRECT lpTrueRect):获取对象所占矩形的大小,如果边框形式为CRectTracker::hatchOutside则矩形大小包括外部调整句柄的范围

Int HitTest(Cpoint point):函数返回光标在CrectTrack类中的位置,通过返回值可以确定拖动句柄的位置
CRectTracker::hitNothing –1:  没有点击任何地方
CRectTracker::hitTopLeft 0 : 点击调整标记的左上角
CRectTracker::hitTopRight 1 : 点击调整标记的右上角
CRectTracker::hitBottomRight 2: 点击调整标记的右下角
CRectTracker:hitBottomLeft 3:  点击调整标记的左下角
CRectTracker:hitTop 4 :     点击调整标记的上方
CRectTracker:hitRight 5:     点击调整标记的右方
CRectTracker:hitBottom 6:    点击调整标记的下方
CRectTracker:hitLeft 7:     点击调整标记的左方
CRectTracker:hitMiddle 8:    点击调整标记的中央


BOOL SetCursor(CWnd* pWnd,UINT nHitTest):当点击特定的位置时改变光标的形状

二 .应用示例

整个程序界面如下,我们可以通过工具栏来设置图像的边界和调整句柄的类型,同时我们可以用鼠标移动和调整整个图像,另外程序还支持用←↑→↓来微调矩形的位置,通过Shift+←↑→↓来微调矩形的大小.程序的开发步骤如下:

步骤一:使用VC的MFC AppWizard创建单文档应用程序ExamTracker,创建过程中保留默认值。
步骤二.在CExamTrackerDoc中增加两个成员变量
CRectTracker m_tracker;
BOOL m_bAllowInvert:是否允许逆向拖动,即橡皮条的落点是否小于起点。
步骤三:在CrectTrckerDemoDoc的构造函数中给m_tracker对象赋初值
m_tracker.m_rect.left = 200;
m_tracker.m_rect.top = 100;
m_tracker.m_rect.right = 301;
m_tracker.m_rect.bottom = 201;
//初始边界形式为实线
m_tracker.m_nStyle=CRectTracker::solidLine;
//允许逆向拖动
m_bAllowInvert=TRUE;
步骤四;在CExamTrackerView中编写函数OnDraw()绘制图像所示的矩形.下面的代码相信大家都看的懂.void CExamTrackerView::OnDraw(CDC* pDC){
CExamTrackerDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
CBrush* pOldBrush = NULL;
TRY
{
//用不同的画刷绘制矩形
CBrush brush1, brush2;
CRect rect;
int nWidth = pDoc->m_tracker.m_rect.Width();
int nHeight = pDoc->m_tracker.m_rect.Height();
int nSgnX = nWidth != 0 ? nWidth / abs(nWidth) : 1;
int nSgnY = nHeight != 0 ? nHeight / abs(nHeight) : 1;
pDC->SetTextAlign(TA_CENTER);//设置字体显示方式为中间对齐方式
pDC->SetBkMode(TRANSPARENT);//设置背景色为透明色
int nCenterX, nCenterY;
TEXTMETRIC tm;
pDC->GetTextMetrics(&tm);//获取字体大小
brush1.CreateSolidBrush(RGB(255, 0, 0));
pOldBrush = pDC->SelectObject(&brush1);
//设置第一个图形区域矩形的大小函数为自定义.
SetNormalRect(rect, pDoc->m_tracker.m_rect.left,
pDoc->m_tracker.m_rect.top, nWidth/2, nHeight/2);
//绘制矩形
pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);
nCenterX = rect.left + rect.Width()/2;
nCenterY = rect.top + rect.Height()/2 - tm.tmHeight/2;
     //在矩形中央显示字符1
pDC->ExtTextOut(nCenterX, nCenterY, ETO_CLIPPED, rect, _T("1"), 1, NULL);

brush2.CreateSolidBrush(RGB(0, 255, 0));
pDC->SelectObject(&brush2);
brush1.DeleteObject();
SetNormalRect(rect, pDoc->m_tracker.m_rect.left+nWidth/2,
pDoc->m_tracker.m_rect.top, (nWidth+nSgnX)/2, nHeight/2);
pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);
nCenterX = rect.left + rect.Width()/2;
nCenterY = rect.top + rect.Height()/2 - tm.tmHeight/2;
pDC->ExtTextOut(nCenterX, nCenterY, ETO_CLIPPED, rect, _T("2"), 1, NULL);
brush1.CreateSolidBrush(RGB(0, 0, 255));
pDC->SelectObject(&brush1);
brush2.DeleteObject();
SetNormalRect(rect, pDoc->m_tracker.m_rect.left,
pDoc->m_tracker.m_rect.top+nHeight/2, nWidth/2, (nHeight+nSgnY)/2);
pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);
nCenterX = rect.left + rect.Width()/2;
nCenterY = rect.top + rect.Height()/2 - tm.tmHeight/2;
pDC->ExtTextOut(nCenterX, nCenterY, ETO_CLIPPED, rect, _T("3"), 1, NULL);
brush2.CreateSolidBrush(RGB(192, 192, 192));
pDC->SelectObject(&brush2);
brush1.DeleteObject();
SetNormalRect(rect, pDoc->m_tracker.m_rect.left+nWidth/2,
pDoc->m_tracker.m_rect.top+nHeight/2,
(nWidth+nSgnX)/2, (nHeight+nSgnY)/2);
pDC->PatBlt(rect.left, rect.top, rect.Width(), rect.Height(), PATCOPY);
nCenterX = rect.left + rect.Width()/2;
nCenterY = rect.top + rect.Height()/2 - tm.tmHeight/2;
pDC->ExtTextOut(nCenterX, nCenterY, ETO_CLIPPED, rect, _T("4"), 1, NULL);
// cleanup DC
if (pOldBrush != NULL)
pDC->SelectObject(pOldBrush);
brush2.DeleteObject();
//这一行代码是必不可少的,通过它可以绘制限定形式的图形区域的外部边界和内部区域.
pDoc->m_tracker.Draw(pDC);
}
CATCH_ALL(e)
{
if (pOldBrush != NULL)
pDC->SelectObject(pOldBrush);
}
END_CATCH_ALL
}
在程序中用到了自定义的全局函数static void SetNormalRect(CRect& rect, int left, int top, int width, int height),函数用来设置矩形的大小,同时对矩形进行相应的校正.这种校正一般在逆向拖动时候需要,作用相当于CRect::NormalizeRect().函数定义如下:
static void SetNormalRect(CRect& rect, int left, int top, int width, int height)
{
rect.left = left;
rect.top = top;
rect.right = left + width;
rect.bottom = top + height;
int nTemp;
if (rect.left > rect.right)
{
nTemp = rect.left;
rect.left = rect.right;
rect.right = nTemp;
}
if (rect.top > rect.bottom)
{
nTemp = rect.top;
rect.top = rect.bottom;
rect.bottom = nTemp;
}
}