1,首先来看看相关的一些知识点
1)RECT structure [MSDN]
The RECT structure defines the coordinates(坐标) of the upper-left(左上角) and lower-right(右下角) corners of a rectangle.
typedef struct tagRECT { LONG left; //Specifies the x-coordinate of the upper-left corner of a rectangle.左上角x的坐标 LONG top; //Specifies the y-coordinate of the upper-left corner of a rectangle. 左上角y的坐标 LONG right; //Specifies the x-coordinate of the lower-right corner of a rectangle. 右下角x的坐标 LONG bottom; //Specifies the y-coordinate of the lower-right corner of a rectangle. 右下角y的坐标 } RECT;
2)RECT结构和类CRect CRect Similar to a Windows RECT structure.
class CRect : public tagRECT
This class is derived from the tagRECT structure. (The name tagRECT is a less-commonly-used name for the RECT
structure.) This means that the data members (left, top, right, and bottom) of the RECT structure are accessible
data members of CRect. CRect类派生于RECT结构,因此其对象也可以访问RECT结构的数据成员。
3)如何确定矩形(rectangle)和椭圆(ellipse)
矩形是通过左上角和右下角两个点来确定
椭圆则是在确定好矩形后,做一个内切椭圆。每一个矩形可唯一确定一个内接椭圆。因此椭圆也是由两个点确定,左上角和右下角点。
4)基类的指针虽然指向派生类对象,除了虚函数情况,无法访问派生类的成员函数。相反派生类的指针可以访问基类的成员。
以下面例子为例:
当我们定义RECT *rect时,由于rect=new CRect(cp,cp),即基类的指针指向了派生类对象。而在ondraw函数中,width()和height()是类CRect的函数,此时rect无法访问width()和height()。因此这里用派生类的指针 CRect *rect
5)CWnd::Invalidate
该函数的作用是使整个窗口客户区无效。窗口的客户区无效意味着需要重绘,因此会通过发送wm_paint消息调用ondraw函数实现重绘。
CWnd::Invalidate()和CWnd::UpdateWindow()。
关于两者的一个讨论见:http://topic.csdn.net/t/20020719/14/886666.html。简单的说,invalidate会使客户区域马上无效,从而调用ondraw函数,而undatewindown不会马上使客户区无效从而调用ondraw函数,它会在发现客户区存在无效时调用ondraw函数,比如用另一个从窗口覆盖时。
2,本例子的功能是 在 view 上画一个椭圆。通过鼠标拖动自动画,每次画椭圆之前都删除以前画的椭圆 。
一 . 首先建立一个单文档程序,名字为:DrawEllipse
二 . 然后在CDrawEllipseView 类中添加成员变量:
public:
RECT *rect; //正确的是CRect *rect;当然也可以直接CRect rect,那就不用在构造函数中初始化了。
BOOL m_flag;
三 . 在CDrawEllipseView 类构造器中添加初始化代码:
CDrawEllipseView::CDrawEllipseView()
{
// TODO: add construction code here
CPoint cp(0,0);
rect=new CRect(cp,cp);
m_flag=false;
}
四 . 添加 消息映射代码
ON_WM_MOUSEMOVE:
void CDrawEllipseView::OnMouseMove(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
if(m_flag)
{
rect.right=point.x;
rect.bottom=point.y;
Invalidate();
}
CView::OnMouseMove(nFlags, point);
}
ON_WM_LBUTTONDOWN:
void CDrawEllipseView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CView::OnLButtonDown(nFlags, point);
m_flag=true;
rect.left=point.x;
rect.top=point.y;
}
ON_WM_LBUTTONUP:
void CDrawEllipseView::OnLButtonUp(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
m_flag=false;
CView::OnLButtonUp(nFlags, point);
}
五 . 重写OnDraw
void CDrawEllipseView::OnDraw(CDC* pDC)
{
CDrawEllipseDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if(rect.Width()>10 && rect.Height()>10)
{
CPen penA(PS_DOT,1,RGB(255,0,0));
CPen * pOldPen=NULL;
pOldPen=pDC->SelectObject(&penA);
pDC->SelectStockObject(NULL_BRUSH);
pDC->Ellipse(rect);
pDC->SelectObject(pOldPen);
}
// TODO: add draw code for native data here
}