程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> C語言 >> VC >> 關於VC++ >> CRectTracker類的使用

CRectTracker類的使用

編輯:關於VC++

本文配套源碼下載

CRectTracker(俗稱“橡皮筋”類)是一個非常有意思的類。你在Windows中經常看到這樣的情況:它可以用做顯示邊界,你也可以扽它的八個角用來放大縮小,或做框選使用。如何通過編程來實現這種功能呢?這就是CRectTracker類的作用;

(框選)             (顯示邊界並可以縮放)

你打開上面的那個工程文件,編譯運行一下。你將看到CRectTracker的幾種功能;

下面讓我們來從頭做一個新的工程文件,來慢慢掌握它的功能吧。

建立一個單文檔的工程文件,將其命名為Rect。單擊finish完成工程的建立;先編譯一下,來第一次生成obj文件吧,在它生成的過程中,我們繼續往下講解;

第一步:

在CRectDoc類中生成一個公有的數據成員:m_rectTracker;之所以設成公有,因為要在View中調用它。接著我們來初始化它,在CRectDoc::CrectDoc構造函數中:

CRectDoc::CRectDoc()
{ // TODO: add one-time construction code here
    m_rectTracker.m_rect.SetRect(0,0,100,100);
    m_rectTracker.m_nStyle=CRectTracker::resizeInside|CRectTracker::dottedLine;
 }

其中: m_rect是CRectTracker中用來控制四邊形的大小位置的數據成員, SetRect使用的是View的坐標; m_nStyle是CRectTracker的類型,其中:CRectTracker::resizeInside和CRectTracker::resizeOutside是說明在m_rect的內部還是外部畫區域(它們是互異的),CrectTrakcer::dottedLine是用點劃線來畫四邊形的區域邊界。 其他的值還有: CRectTracker::solidLine:用來畫實線邊界;(和dottedLine是互異的) CRectTracker::hatchedBorder:邊界帶拋面線; CRectTracker::hatchInside:內部帶拋面線; 你可以運行前面的例子,上述參數都有使用。你也可以在第二步中逐一使用它們來加深理解它們各自的含義;

第二步:

接著我門在視圖中畫一個藍色的橢圓; 在CRectView的OnDraw中繼續我們的工作:

void CRectView::OnDraw(CDC* pDC)
{
   CRectDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   // TODO: add draw code for native data here
   CBrush brush(RGB(0,0,255));//生成藍色的畫刷;
   CBrush *oldBrush=pDC->SelectObject(&brush);//將畫刷選進dc;
   CRect rect;
   //GetTrueRect(&rect)得到CRectTracker中的m_rect的大小,將其傳遞給rect;
   pDoc->m_rectTracker.GetTrueRect(&rect);
   pDC->Ellipse (rect);//畫橢圓;
   //Draw tracking rectangle.
   pDoc->m_rectTracker.Draw(pDC);//這句畫才真正的將這個四邊形畫出來;
   //Select blue brush out of device context.
   pDC->SelectObject (oldBrush);//恢復原來的畫刷;
}

注釋已經在程序裡了,不用再多說,編譯一下。一個橢圓外帶四邊形邊界(點劃線),且四邊形的四周有八個黑點;這就是CRectTracker.,你現在可以改變一下m_nStyle試試看各參數的含義;

第三步:如何象例子中的那樣隨著鼠標的移動自動在橢圓的周圍改變光標呢?很簡單只要將下面的代碼加入到CRectView::OnSetCursor()就可以了:它調用了CRectTracker中的SetCursor()函數:

BOOL CRectView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{ // TODO: Add your message handler code here and/or call default
   CRectDoc* pDoc = GetDocument();
   if (pWnd == this && pDoc->m_rectTracker.SetCursor(this, nHitTest))
     return TRUE;
   return CView::OnSetCursor(pWnd, nHitTest, message);
}

編譯運行一下,鼠標變化了。 第四步:我們再做另一個用於鼠標的CRectTracker類。它的作用是在鼠標按下以後可以顯示虛線的選擇框: 先讓我們看看效果:

在CRectView中的加入如下代碼:

void CRectView::OnLButtonDown(UINT nFlags, CPoint point)
{
  CRectTracker temp;
  temp.TrackRubberBand(this,point,TRUE);
  temp.m_rect.NormalizeRect();//正規化;
  CView::OnLButtonDown(nFlags, point);
}

編譯運行,當你按下鼠標並拖動,你將看到效果了。

我們如何讓鼠標畫一個“橡皮筋”區域呢? 在CRectTracker類中的成員函數就是:TrackRubberBand(this,point,TRUE); 注意其中的三個參數:

第一個參數,畫“橡皮筋”的窗體的指針,當然是this

第二個參數,畫“橡皮筋”的起始點。

讓我們注意第三個參數,它非常有意思。當你使用FALSE時(TRUE 值是缺省的),你的“橡皮筋”只能從左上到右下的畫,不允許反向。編譯運行一下FALSE這個值。

特別值得注意的是:在TrackRubberBand的過程中是以右鍵的抬起為結束的,這其間並沒有CView的MouseMove發生。這一點一定要記住!這時鼠標畫過的區域已經記錄在temp的m_rect 中了,你可以根據它進行後續的判斷工作。至於下面的正規化語句函數的作用與CRect中的正規化函數的作用一致:使四邊形的四個角的坐標符合右大於左,底大於頂的坐標值。它主要是為了防止你使用TrackRubberBand 的FALSE參數而引起的可能出現的錯誤。

第五步:

讓我們回到那個藍色的橢圓,在開始新的步驟之前,首先來介紹一下HitTest(CPoint point)的功能:當你鼠標被按下的時候,你可以調用這個函數,它將返回鼠標點在了四邊形的什麼位置:

返回值 代表的含義 -1 點在了四邊形的外部 0 左上角 1 右上角 2 右下角 3 左下角(0,1,2,3順時針轉了一圈) 4 頂部 5 右部 6 底部 7 左部(還是順時針轉了一圈) 8 點在了四邊形的內部,但沒有擊中前面的那八個點

可以看出,返回值如果大於等於零則在四邊形區域之內。如果小於則說明不在區域范圍之內。因此我們需要加一個公有的成員函數:BOOL bDraw;為了方便起見,我把它加到CRectView中,(你也許會說,為什麼不加到doc中,我也知道這有勃編程的原理,反正我高興就得,都說C++給人了很大的自由度,所以你也別限制我)。先把它初始化為FALSE,表示不畫邊界,當TRUE時,表示要畫邊界。 定義: class CRectView : public CView
{
  …………
  public:
  BOOL bDraw;
  …….
}
初始化:
CRectView::CRectView()
{
   // TODO: add construction code here
   bDraw=FALSE;
}
將OnDraw改一下,加一句話:
void CRectView::OnDraw(CDC* pDC)
{
   CRectDoc* pDoc = GetDocument();
   ASSERT_VALID(pDoc);
   // TODO: add draw code for native data here
   CBrush brush(RGB(0,0,255));//生成藍色的畫刷;
   CBrush *oldBrush=pDC->SelectObject(&brush);//將畫刷選進dc;
   CRect rect;
   pDoc->m_rectTracker.GetTrueRect (&rect);
   //GetTrueRect(&rect)可以得到CRectTracker中的m_rect的大小,將其傳遞給rect;
   if(bDraw) //*************新加的語句***************
     pDC->Ellipse (rect);//畫橢圓;
    //Draw tracking rectangle.
   pDoc->m_rectTracker.Draw (pDC);//***這句畫才真正的將這個四邊形畫出來;***
   //Select blue brush out of device context.
   pDC->SelectObject (oldBrush);//恢復原來的畫刷;
}
   編譯運行一下,橢圓的邊界沒有了。
   好了,預備知識講完了,讓我們來完成這個程序吧:
void CRectView::OnLButtonDown(UINT nFlags, CPoint point)
{
   // TODO: Add your message handler code here and/or call default
   int nIn; //定義一個鼠標的點擊值;
   nIn=GetDocument()->m_rectTracker.HitTest(point); //看看點到了哪了
   if(nIn<0) //不在四邊形區域內;
   {
   CRectTracker temp;
   temp.TrackRubberBand(this,point,TRUE);
   temp.m_rect.NormalizeRect();
   CRectTracker interRect;
   //在建立一個CRectTracker;用於記錄鼠標與橢圓的交集。
   if(interRect.m_rect.IntersectRect(temp.m_rect,GetDocument()->m_rectTracker.m_rect))
    bDraw=TRUE; //如果有交集,則畫四邊形的邊界,說明選擇了橢圓
   else  bDraw=FALSE;
   Invalidate(); //引起OnDraw函數的發生;
   }
   else
    //在四邊形區域內:
   {
   CClientDC dc(this);
   GetDocument()->m_rectTracker.Draw(&dc);
   GetDocument()->m_rectTracker.Track(this,point,TRUE);
   // Track()是CRectTracker中最富魅力的函數。它時時的改變調用者的m_rect;
   bDraw=TRUE;
   Invalidate();
   }
   CView::OnLButtonDown(nFlags, point);
}

你也許會問,為什麼我沒有編寫MouseMove函數,它就自動的變大小了呢?這就是Track()函數的功勞,從調用它到抬起鼠標鍵為止,它時刻的改變m_rectTracker的四邊形的大小。然後由於我們使用了Invalidate()函數,所以重新畫了這個橢圓,因此它好象被放大縮小了似的。 我的文章寫完了,還有什麼不懂的地方,寫信給我。在關閉這個文件之前,最好你自己再復習一下,並嘗試一下其他的功能。

  1. 上一頁:
  2. 下一頁:
欄目導航
Copyright © 程式師世界 All Rights Reserved