380 likes | 598 Views
MFC GUI 编程. Greetings. Hello, World!. class CGreetingsDoc : public CDocument { protected: // create from serialization only char *m_pMessage; // Attributes public: char *GetGreetings() { return m_pMessage; } … } CGreetingsDoc::CGreetingsDoc() {
E N D
Hello, World! • class CGreetingsDoc : public CDocument • { • protected: // create from serialization only • char *m_pMessage; • // Attributes • public: • char *GetGreetings() • { • return m_pMessage; • } • … • } • CGreetingsDoc::CGreetingsDoc() • { • m_pMessage = "Hello, world!"; • }
void CGreetingsView::OnDraw(CDC* pDC) • { • CGreetingsDoc* pDoc = GetDocument(); • ASSERT_VALID(pDoc); • RECT ClientRect; • GetClientRect(&ClientRect); • pDC->DrawText( pDoc->GetGreetings(), -1, &ClientRect, DT_CENTER ); • }
Button • void CGreetingsView::OnButtongreetings() • { • AfxMessageBox("Hello, world!"); • }
MiniDraw • 用户可以画不同的图形元素 • Line, rectangle, ellipse, polygon… • demo
Member Variables • class CMiniDrawView : public CView • { • private: • int m_Dragging; • CPoint m_PointOld; • CPoint m_PointOrigin; • } • CMiniDrawView::CMiniDrawView() • { • m_Dragging = 0; • }
响应消息 • ClassWizard (^W)
WM_LBUTTONDOWN • void CMiniDrawView::OnLButtonDown(UINT nFlags, CPoint point) • { • //AfxMessageBox("button down"); • m_PointOrigin = point; • m_PointOld = point; • m_Dragging = 1; • CView::OnLButtonDown(nFlags, point); • }
WM_MOUSEMOVE • void CMiniDrawView::OnMouseMove(UINT nFlags, CPoint point) • { • if( !m_Dragging ) • return; • CClientDC ClientDC( this ); • ClientDC.SetROP2( R2_NOT ); • ClientDC.MoveTo( m_PointOrigin ); • ClientDC.LineTo( m_PointOld ); • ClientDC.MoveTo( m_PointOrigin ); • ClientDC.LineTo( point ); • m_PointOld = point; • CView::OnMouseMove(nFlags, point); • }
WM_LBUTTONUP • void CMiniDrawView::OnLButtonUp(UINT nFlags, CPoint point) • { • if( !m_Dragging ) • return ; • CClientDC ClientDC( this ); • ClientDC.SetROP2( R2_NOT ); • ClientDC.MoveTo( m_PointOrigin ); • ClientDC.LineTo( m_PointOld ); • ClientDC.SetROP2( R2_COPYPEN ); • ClientDC.MoveTo( m_PointOrigin ); • ClientDC.LineTo( point ); • m_Dragging = 0; • CView::OnLButtonUp(nFlags, point); • }
Problem • 窗口更新后线段消失了 • 原因? • 没有存储数据
线段数据结构 • class CLine • { • private: • int m_X1, m_Y1, m_X2, m_Y2; • public: • CLine(int X1, int Y1, int X2, int Y2 ) • { • m_X1 = X1; • m_Y1 = Y1; • m_X2 = X2; • m_Y2 = Y2; • } • void Draw( CDC *pDC ) • { • pDC->MoveTo( m_X1, m_Y1 ); • pDC->LineTo( m_X2, m_Y2 ); • } • };
保存线段的数组 • class CMiniDrawView : public CView • { • vector<CLine *> m_LineArray; • … • } • #include <vector> • using namespace std;
保存线段数据 • void CMiniDrawView::OnLButtonUp(UINT nFlags, CPoint point) • { • // TODO: Add your message handler code here and/or call default • if( m_Dragging ) • { • CClientDC ClientDC( this ); • ClientDC.SetROP2( R2_NOT ); • ClientDC.MoveTo( m_PointOrigin ); • ClientDC.LineTo( m_PointOld ); • ClientDC.SetROP2( R2_COPYPEN ); • ClientDC.MoveTo( m_PointOrigin ); • ClientDC.LineTo( point ); • m_Dragging = 0; • CLine *pLine = NULL; • pLine = new CLine(m_PointOrigin.x, m_PointOrigin.y, • point.x, point.y ); • m_LineArray.push_back( pLine ); • }
重画所有线段 • void CMiniDrawView::OnDraw(CDC* pDC) • { • CMiniDrawDoc* pDoc = GetDocument(); • ASSERT_VALID(pDoc); • // TODO: add draw code for native data here • for( int i=0; i<m_LineArray.size(); i++) • { • m_LineArray.at(i)->Draw(pDC); • } • }
如何检测有无内存泄漏 • Debug information
释放空间 • CMiniDrawView::~CMiniDrawView() • { • for( int i=0; i<m_LineArray.size(); i++) • { • SAFEDELETE( m_LineArray.at(i) ); • } • } • #define SAFEDELETE(p) {if(p){delete p; p=NULL;}}
3. 更多图形元素 • 不同类型图形元素如何存储? • 如何组织它们之间的关系?
椭圆图形及数据结构 • class CEllipse • { • private: • int m_X1, m_Y1, m_X2, m_Y2; • public: • CEllipse(int X1, int Y1, int X2, int Y2 ) • { • m_X1 = X1; • m_Y1 = Y1; • m_X2 = X2; • m_Y2 = Y2; • } • void Draw( CDC *pDC ) • { • pDC->Ellipse( m_X1, m_Y1, m_X2, m_Y2 ); • } • };
??? • vector<CLine *> m_LineArray; • vector<CEllipse *> m_EllipseArray; • …
4. 父类和继承 • class CFigure • { • public: • virtual void Draw( CDC *pDC ) {} //虚函数 • }; • class CLine: public CFigure • class CEllipse: public CFigure
5. 图形数组 • class CMiniDrawView : public CView • { • vector<CFigure *> m_FigArray; • UINT m_CurrentTool; //图形类型 • } • //数据初始化 • CMiniDrawView::CMiniDrawView() • { • m_CurrentTool = ID_BUTTONLINE; • } • 替换m_LineArraym_FigArray • CFigure *pFigure = NULL; • pFigure = new CLine (m_PointOrigin.x, m_PointOrigin.y, • point.x, point.y ); • m_FigArray.push_back( pFigure );
图形类型 • void CMiniDrawView::OnButtonline() • { • m_CurrentTool = ID_BUTTONLINE; • } • void CMiniDrawView::OnButtonellipse() • { • m_CurrentTool = ID_BUTTONELLIPSE; • }
OnMouseMove • void CMiniDrawView::OnMouseMove(UINT nFlags, CPoint point) • { • if( !m_Dragging ) • return ; • CClientDC ClientDC( this ); • ClientDC.SelectStockObject (NULL_BRUSH); • switch (m_CurrentTool) • { • case ID_BUTTONLINE: • ClientDC.SetROP2( R2_NOT ); • ClientDC.MoveTo( m_PointOrigin ); • ClientDC.LineTo( m_PointOld ); • ClientDC.MoveTo( m_PointOrigin ); • ClientDC.LineTo( point ); • break; • case ID_BUTTONELLIPSE: • ClientDC.SetROP2 (R2_NOT); • ClientDC.Ellipse (m_PointOrigin.x, m_PointOrigin.y, m_PointOld.x, m_PointOld.y ); • ClientDC.Ellipse (m_PointOrigin.x, m_PointOrigin.y, point.x, point.y ); • break; • } • m_PointOld = point; • CView::OnMouseMove(nFlags, point); • }
OnLButtonUp • void CMiniDrawView::OnLButtonUp(UINT nFlags, CPoint point) • { • if( !m_Dragging ) • return; • CClientDC ClientDC( this ); • ClientDC.SelectStockObject (NULL_BRUSH); • CFigure *pFigure = NULL; • switch (m_CurrentTool) • { • case ID_BUTTONLINE: • ClientDC.SetROP2( R2_NOT ); • ClientDC.MoveTo( m_PointOrigin ); • ClientDC.LineTo( m_PointOld ); • pFigure = new CLine(m_PointOrigin.x, m_PointOrigin.y, • point.x, point.y ); • break; • case ID_BUTTONELLIPSE: • ClientDC.SetROP2 (R2_NOT); • ClientDC.Ellipse (m_PointOrigin.x, m_PointOrigin.y, m_PointOld.x, m_PointOld.y ); • pFigure = new CEllipse (m_PointOrigin.x, m_PointOrigin.y, point.x, point.y); • break; • } • ClientDC.SetROP2 (R2_COPYPEN); • pFigure->Draw (&ClientDC); • m_FigArray.push_back( pFigure ); • m_Dragging = 0; • CView::OnLButtonUp(nFlags, point); • }
6. 多态性 • void CMiniDrawView::OnDraw(CDC* pDC) • { • CMiniDrawDoc* pDoc = GetDocument(); • ASSERT_VALID(pDoc); • // TODO: add draw code for native data here • pDC->SelectStockObject (NULL_BRUSH); • for( int i=0; i<m_FigArray.size(); i++) • { • m_FigArray.at(i)->Draw(pDC); • } • }
线框画图模式 • CMiniDrawView:: OnMouseMove() • CMiniDrawView::OnLButtonUp() • CClientDC ClientDC( this ); • ClientDC.SelectStockObject (NULL_BRUSH); • CMiniDrawView::OnDraw() • pDC->SelectStockObject (NULL_BRUSH);
类的分离 • Figure.h/cpp
总结 • STL vector • GDI画图 • 鼠标交互 • 消息响应(鼠标) • 按钮 • 类的继承和多态
作业3--MiniDraw • 完善MiniDraw画图程序 • 写一个画图小程序MiniDraw,要求画直线(Line),椭圆(Ellipse),矩形(Rectangle),多边形(Polygon)等图形元素(图元) • 每种图元需用一个类(对象)来封装,如CLine, CEllipse, CRect, CPolygon, CFreehand; • 各种图元从一个父类CFigure来继承; • 学习类的继承和多态
要求 • 至少完成直线(Line),椭圆(Ellipse),矩形(Rectangle),多边形(Polygon) ,自由手绘线(Freehand)等图形元素 • Deadline: 9:30a.m. April 6, 2011
如何学好VC • 需要有好的C/C++基础 • 理解Windows的消息机制,窗口句柄和其他GUI句柄的含义和用途 • 多使用Online Help • 记住一些常用的消息名称和参数的意义 • 学会看别人的代码 • 多练习,在实践中成长!
References • VC入门级书籍 • Windows编程 • 《MFC深入浅出》