CRectTracker(俗稱“橡皮筋”類)是一個非常有意思的類。你在Windows中經常看到這樣的情況:它可以用做顯示邊界,你也可以扽它的八個角用來放大縮小,或做框選使用。如何通過編程來實現這種功能呢?這就是CRectTracker類的作用。下圖是這個程序運行的結果:
下面讓我們來從頭做一個新的工程文件,來慢慢掌握它的功能吧。
建立一個單文檔的工程文件,將其命名為RectTracke。單擊finish完成工程的建立;先編譯一下,第一次生成obj文件吧,在它生成的過程中,我們繼續往下講解;
第一步:
在CRectTrackeDoc類中生成一個公有的數據成員:m_RectTracker;之所以設成公有,因為要在View中調用它。
class CRectTrackeDoc : public CDocument { protected: // create from serialization only CRectTrackeDoc(); DECLARE_DYNCREATE(CRectTrackeDoc) // Attributes public: CRectTracker m_RectTracker;
接着我們來初始化它,在CRectTrackeDoc構造函數中:
CRectTrackeDoc::CRectTrackeDoc() { // TODO: add one-time construction code here m_RectTracker.m_rect.SetRect(200,200,100,100); //矩形位置 m_RectTracker.m_nStyle = CRectTracker::dottedLine | CRectTracker::resizeInside; }
其中: m_rect是CRectTracker中用來控制四邊形的大小位置的數據成員, SetRect使用的是View的坐標; m_nStyle是CRectTracker的類型,CRectTracker::resizeInside和CRectTracker::resizeOutside是說明在m_rect的內部還是外部畫區域(它們是互異的),CrectTrakcer::dottedLine是用點划線來畫四邊形的區域邊界。 其他的值還有: CRectTracker::solidLine:用來畫實線邊界;(和dottedLine是互異的) CRectTracker::hatchedBorder:邊界帶拋面線; CRectTracker::hatchInside:內部帶拋面線; 你可以運行前面的例子,上述參數都有使用。你也可以在第二步中逐一使用它們來加深理解它們各自的含義;
第二步:
在CRectTrackeView 類中添加一個公有成員變量bDraw,用來判斷是否需要在矩形框中畫橢圓
class CRectTrackeView : public CView { protected: // create from serialization only CRectTrackeView(); DECLARE_DYNCREATE(CRectTrackeView) // Attributes public: CRectTrackeDoc* GetDocument(); BOOL bDraw;
在構造函數中初始化bDraw = false,表示初始時不在矩形寬中畫橢圓,只有鼠標左鍵按下時,bDraw為true.才進行畫橢圓操作
CRectTrackeView::CRectTrackeView() { // TODO: add construction code here bDraw = FALSE; }
第三步:
接着我門在視圖中畫一個藍色的橢圓; 在CRectView的OnDraw中繼續我們的工作:
void CRectTrackeView::OnDraw(CDC* pDC) { CRectTrackeDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); CBrush brush(RGB(0,0,255)); CBrush * oldBrush = pDC->SelectObject(&brush); CRect rect; pDoc->m_RectTracker.GetTrueRect(&rect); //得到CRectTracker中的m_rect的大小,將其傳遞給rect; if(bDraw) { pDC->Ellipse(&rect); } pDoc->m_RectTracker.Draw(pDC); //這句畫才真正的將這個四邊形畫出來; pDC->SelectObject(oldBrush); // TODO: add draw code for native data here }
這個時候運行程序,將會看到在視類客戶區200,200,100,100的位置出現一個矩形區域,因為bDraw參數為false,此時並沒有畫出橢圓。如下圖:
第四步:
如何像例子中的那樣隨着鼠標的移動自動在橢圓的周圍改變光標呢?很簡單只要將下面的代碼加入到CRectTrackeView::OnSetCursor()就可以了:它調用了CRectTracker中的SetCursor()函數。 注意:OnSetCursor是一個消息響應函數,當鼠標在改矩形區域中的時候,會產出消息,並調用OnSetCursor函數。
BOOL CRectTrackeView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) { // TODO: Add your message handler code here and/or call default CRectTrackeDoc* pDoc = GetDocument(); if((pWnd == this) && (pDoc->m_RectTracker.SetCursor(this,nHitTest))) { return TRUE; } return CView::OnSetCursor(pWnd, nHitTest, message); }
編譯運行一下,鼠標變化了。
第五步:
添加鼠標左鍵按下消息響應函數,該函數功能呢:當在矩形區域內點擊左鍵並拖動的時候,則在矩形區域內把橢圓繪制出來, 當在矩形區域外點擊鼠標左鍵並拖動的時候,則重新繪制一個矩形區域。運行結果如第一張圖。
void CRectTrackeView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: Add your message handler code here and/or call default //判斷鼠標點擊的區域是在哪里,在在矩形區域內,還是區域外 int nRetCode = GetDocument()->m_RectTracker.HitTest(point); if(nRetCode < 0) //不在矩形區域 { //給temp變量初始化 CRectTracker temp; temp.m_rect.SetRect(0,0,0,0); temp.m_nStyle = CRectTracker::dottedLine | CRectTracker::resizeInside; //TrackRubberBand函數直到鼠標左鍵提起的時候才會返回,並把左鍵提起的位置也記錄了下來 //該函數過程中,不會產生鼠標移動消息 temp.TrackRubberBand(this,point,TRUE); //使得矩形為正確的坐標,不會出現負的坐標 temp.m_rect.NormalizeRect(); //此時把bDraw設為false bDraw = FALSE; CClientDC dc(this); //把新的矩形區域繪制出來 temp.Draw(&dc); } else //在矩形區域內 { //Track和TrackRubberBand類似,直到鼠標左鍵提起的時候才會返回,並把左鍵提起的位置也記錄了下來 //該函數過程中,不會產生鼠標移動消息 GetDocument()->m_RectTracker.Track(this,point,TRUE); //設置為true,則需要在矩形內繪制橢圓 bDraw = TRUE; //窗口無效,調用Onpaint函數 Invalidate(TRUE); } 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)的功能:當你鼠標被按下的時候,你可以調用這個函數,它將返回鼠標點在了四邊形的什么位置:
以上就是CRectTracker類的用法。