C++编程逻辑讲解step by step:多态

概念

 C++面向对象中的多态性是指同一种类型的对象在不同的情况下表现出不同的行为

从代码层面看,实际上“同一种类型”就表明了,这里可以在循环里用相同的代码统一处理不同的功能。这一点很重要。

题目

界面上,拖动鼠标画矩形或者椭圆。

分析

先定义出矩形CShpRectangle和椭圆类CShpEllipse。因为要实现多态,还要先声明一个基类CShape,基类里有一个绘图功能Draw(),而且还得说明成虚函数,就是要“表现出不同的行为”。

这里用VC++代码,CObject是所有类的祖宗,所以都得从CObject继承过来。

class CShape : public CObject  
{
public:

....

    virtual void Draw(CDC* pDC) 
                     { TRACE("My Error: In CShape::Draw.\n");
                         ASSERT(FALSE); };

};

class CShpRectangle : public CShape
{
public:
    void Draw(CDC* pDC);    // Overrides CShape::Draw
};

class CShpEllipse : public CShape
{
public:

    void Draw(CDC* pDC); 

};

定义"不同的行为":

CShape中的Draw()是虚的,所以没功能可定义;

void CShpRectangle::Draw(CDC* pDC)  // Virtual override
{
    pDC->Rectangle(m_boxShape);//根据m_boxShape给的坐标开始画图
}

void CShpEllipse::Draw(CDC* pDC)  // Virtual override
{
    pDC->Ellipse(m_boxShape);
}

处理"不同的行为":

先定义一个基类指针   CShape* pShape; 再让这个指针指向它派生类的对象,这里实际有个强制类型转换,不然基类和派生类毕竟不是同一个类型,经过转换就是同一个类型了。

void CMyDrawView::OnDraw(CDC* pDC)
{......

    CShape* pShape;
    pDoc->SetToOldestShape();
    while(pDoc->GetPos() != NULL)
    {
        pShape = pDoc->GetPrevShape();//GetPrevShape()函数就是做了一个强制转换(CShape*),先不用关注细节
        pShape->Draw(pDC);
    }

}

至此,多态的结构就结束了。其他代码都是各种附加功能:设置画笔风格、画矩形还是椭圆的切换、画的效果等等。

// Shape.h: interface for the CShape class.
//
//

#if !defined(AFX_SHAPE_H__97288485_7254_11D2_991B_00C04FC29F5C__INCLUDED_)
#define AFX_SHAPE_H__97288485_7254_11D2_991B_00C04FC29F5C__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

enum ShpType
{
    shpRectangle,
    shpEllipse
};

class CShape : public CObject  
{
public:
	// Enable MFC serialization (file storage for class objects)
	DECLARE_SERIAL(CShape)

    // Constructors and operators
    // Default constructor 
	CShape();
	// Copy constructor
    CShape(const CShape& s)
    {
        m_boxShape = s.m_boxShape;
        m_bTransparent = s.m_bTransparent;
        m_nColorShape = s.m_nColorShape;
    }

    // Overloaded assignment operator
    CShape& operator=(const CShape& s)
    {
        m_boxShape = s.m_boxShape;
        m_bTransparent = s.m_bTransparent;
        m_nColorShape = s.m_nColorShape;
        return *this;
    }

    // Attributes - deliberately left public for easy access
    // Note: no longer need an m_typeShape member.
    CRect m_boxShape;
    bool m_bTransparent;
    UINT m_nColorShape;

    // Overridables and operations
    virtual void Draw(CDC* pDC) 
                     { TRACE("My Error: In CShape::Draw.\n");
                         ASSERT(FALSE); };

// Implementation
public:
	virtual ~CShape();

};

// Concrete subclass of abstract base class CShape
class CShpRectangle : public CShape
{
public:
    DECLARE_SERIAL(CShpRectangle)

    // Constructors are inherited from CShape.
    // Attributes inherited include:
    //  m_boxShape, m_bTransparent, m_nColorShape

    // Operations
    void Draw(CDC* pDC);    // Overrides CShape::Draw

// Implementation
public:
};

// Concrete subclass of abstract base class CShape
class CShpEllipse : public CShape
{
public:
    DECLARE_SERIAL(CShpEllipse)

    // Constructors are inherited from CShape.
    // Attributes inherited include: 
    //  m_boxShape, m_bTransparent, m_nColorShape

    // Operations
    void Draw(CDC* pDC);    // Overrides CShape::Draw

// Implementation
public:
};

#endif // !defined(AFX_SHAPE_H__97288485_7254_11D2_991B_00C04FC29F5C__INCLUDED_)

// DrawVw.h : interface of the CMyDrawView class
//
/

#if !defined(AFX_DRAWVW_H__24958326_5D0A_11D2_991B_00C04FC29F5C__INCLUDED_)
#define AFX_DRAWVW_H__24958326_5D0A_11D2_991B_00C04FC29F5C__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "DrawDoc.h"

// Array of actual colors, indexed
//  by CMyDrawView::m_nColorNext
static COLORREF arColors[10] =  
{
    RGB(0,0,0),         // Black
    RGB(0,0,255),       // Blue
    RGB(0,255,0),       // Green
    RGB(0,255,255),     // Cyan
    RGB(255,0,0),       // Red
    RGB(255,0,255),     // Magenta
    RGB(255,255,0),     // Yellow
    RGB(255,255,255),   // White
    RGB(128,128,128),   // Dark gray
    RGB(192,192,192)    // Light gray
};

class CMyDrawView : public CView
{
protected: // create from serialization only
	CMyDrawView();
	DECLARE_DYNCREATE(CMyDrawView)

// Attributes
public:
	CMyDrawDoc* GetDocument();
    ShpType m_typeNext;       // Type of CShape to draw next
    CShape* m_pShpTemp;       // The current CShape being drawn
    bool m_bCaptured;         // True if mouse has been captured
    CBrush* m_pBrushOld;      // Store brush for interior of shapes
    bool m_bTransparent;      // True if Transparent selected
	UINT m_nColorNext;        // Store ID for color to simplify 
                              // updating menus
    CPen* m_pPenOld;          // Pen for drawing CShape outlines
    CPen* m_pPenNew;          // Store pens we create

// Operations
public:

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CMyDrawView)
	public:
	virtual void OnDraw(CDC* pDC);  // overridden to draw this view
	virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
	protected:
	virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
	virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
	virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
	//}}AFX_VIRTUAL

// Implementation
public:
	void InvertShape(CDC *pDC, CShape &s, bool bInvert = true);
	void ResetPenBrush(CDC * pDC);
	void SetPenBrush(CDC * pDC, bool bTransparent, UINT nColor);
	virtual ~CMyDrawView();
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

protected:

// Generated message map functions
protected:
	//{{AFX_MSG(CMyDrawView)
	afx_msg void OnToolRectangle();
	afx_msg void OnToolEllipse();
	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
	afx_msg void OnMouseMove(UINT nFlags, CPoint point);
	afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
	afx_msg void OnUpdateToolRectangle(CCmdUI* pCmdUI);
	afx_msg void OnUpdateToolEllipse(CCmdUI* pCmdUI);
	afx_msg void OnToolTransparent();
	afx_msg void OnUpdateToolTransparent(CCmdUI* pCmdUI);
	//}}AFX_MSG
	afx_msg void OnToolColor(UINT nID);  // ON_COMMAND_RANGE handler
	afx_msg void OnUpdateToolColor(CCmdUI* pCmdUI);
	DECLARE_MESSAGE_MAP()
};

#ifndef _DEBUG  // debug version in DrawVw.cpp
inline CMyDrawDoc* CMyDrawView::GetDocument()
   { return (CMyDrawDoc*)m_pDocument; }
#endif

/

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_DRAWVW_H__24958326_5D0A_11D2_991B_00C04FC29F5C__INCLUDED_)

// DrawDoc.h : interface of the CMyDrawDoc class
//
/

#if !defined(AFX_DRAWDOC_H__24958324_5D0A_11D2_991B_00C04FC29F5C__INCLUDED_)
#define AFX_DRAWDOC_H__24958324_5D0A_11D2_991B_00C04FC29F5C__INCLUDED_

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include "Shape.h"


class CMyDrawDoc : public CDocument
{
protected: // create from serialization only
	CMyDrawDoc();
	DECLARE_DYNCREATE(CMyDrawDoc)

// Attributes
public:
	void SetToOldestShape() { m_pos = m_listShapes.GetTailPosition(); };
	void SetToLatestShape() { m_pos = m_listShapes.GetHeadPosition(); };

	CShape* GetPrevShape()
    {
        // Sets m_pos to NULL if no shapes or if
        //  latest shape is last in list.
        return (CShape*)m_listShapes.GetPrev(m_pos);
    };

	CShape* GetNextShape()
    {
        // Sets m_pos to NULL if no shapes or if
        //  latest shape is last in list
        return (CShape*)m_listShapes.GetNext(m_pos);
    };

	POSITION GetPos() const
    {
        // m_pos tells you where you are in a list of the shapes.
        // Use GetPos with either iteration direction to test for end.
        return m_pos;   // Can be NULL
    };
	
	int GetCount() const
    {
        // Return the number of stored shapes.
        return m_listShapes.GetCount();
    };

private:
    CObList m_listShapes;  // Linked list of all shapes drawn so far
    POSITION m_pos;        // Latest position accessed

// Operations
public:

// Overrides
	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CMyDrawDoc)
	public:
	virtual BOOL OnNewDocument();
	virtual void Serialize(CArchive& ar);
	virtual void DeleteContents();
	//}}AFX_VIRTUAL

// Implementation
public:
	CShape* CreateShape(ShpType st);
	void DeleteAllShapes();
	void DeleteLatestShape();
	virtual ~CMyDrawDoc();
#ifdef _DEBUG
	virtual void AssertValid() const;
	virtual void Dump(CDumpContext& dc) const;
#endif

protected:

// Generated message map functions
protected:
	//{{AFX_MSG(CMyDrawDoc)
		// NOTE - the ClassWizard will add and remove member functions here.
		//    DO NOT EDIT what you see in these blocks of generated code !
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

/

//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.

#endif // !defined(AFX_DRAWDOC_H__24958324_5D0A_11D2_991B_00C04FC29F5C__INCLUDED_)

// DrawDoc.cpp : implementation of the CMyDrawDoc class
//

#include "stdafx.h"
#include "MyDraw.h"

#include "DrawDoc.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/
// CMyDrawDoc

IMPLEMENT_DYNCREATE(CMyDrawDoc, CDocument)

BEGIN_MESSAGE_MAP(CMyDrawDoc, CDocument)
	//{{AFX_MSG_MAP(CMyDrawDoc)
		// NOTE - the ClassWizard will add and remove mapping macros here.
		//    DO NOT EDIT what you see in these blocks of generated code!
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/
// CMyDrawDoc construction/destruction

CMyDrawDoc::CMyDrawDoc()
{
	// TODO: add one-time construction code here
    m_pos = NULL;
}

CMyDrawDoc::~CMyDrawDoc()
{
}

BOOL CMyDrawDoc::OnNewDocument()
{
	if (!CDocument::OnNewDocument())
		return FALSE;

	// TODO: add reinitialization code here
	// (SDI documents will reuse this document)

	return TRUE;
}



/
// CMyDrawDoc serialization

void CMyDrawDoc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: add storing code here
	}
	else
	{
		// TODO: add loading code here
	}
}

/
// CMyDrawDoc diagnostics

#ifdef _DEBUG
void CMyDrawDoc::AssertValid() const
{
	CDocument::AssertValid();
}

void CMyDrawDoc::Dump(CDumpContext& dc) const
{
	CDocument::Dump(dc);
}
#endif //_DEBUG

/
// CMyDrawDoc commands

void CMyDrawDoc::DeleteLatestShape()
{
	ASSERT(!m_listShapes.IsEmpty());
    CShape* pShape = (CShape*)m_listShapes.RemoveHead();
    delete pShape;
}

void CMyDrawDoc::DeleteAllShapes()
{
	POSITION pos = m_listShapes.GetHeadPosition(); // NULL if empty
    while(pos != NULL)
    {
        delete m_listShapes.GetNext(pos);
    }
    m_listShapes.RemoveAll();
    SetModifiedFlag(false); // Nothing to save now
}

void CMyDrawDoc::DeleteContents() 
{
	// TODO: Add your specialized code here and/or call the base class
	DeleteAllShapes();
    UpdateAllViews(NULL);

	CDocument::DeleteContents();
}

CShape* CMyDrawDoc::CreateShape(ShpType st)
{
	ASSERT(st >= shpRectangle && st <= shpEllipse);
    switch(st)
    {
    case shpRectangle:
        {
            CShpRectangle* pRectangle = new CShpRectangle;
            ASSERT(pRectangle != NULL);
            m_listShapes.AddHead(pRectangle);
        }
        break;
    case shpEllipse:
        {
            CShpEllipse* pEllipse = new CShpEllipse;
            ASSERT(pEllipse != NULL);
            m_listShapes.AddHead(pEllipse);
        }
        break;
    default: ;  // Nothing
    }

    // Return the object just created.
    if(m_listShapes.GetCount() > 0)         
        return (CShape*)m_listShapes.GetHead();     
    else
        return NULL;

}

// MyDraw.cpp : Defines the class behaviors for the application.
//

#include "stdafx.h"
#include "MainFrm.h"

#include "MyDraw.h"
#include "DrawVw.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/
// CMyDrawApp

BEGIN_MESSAGE_MAP(CMyDrawApp, CWinApp)
	//{{AFX_MSG_MAP(CMyDrawApp)
	ON_COMMAND(ID_APP_ABOUT, OnAppAbout)
		// NOTE - the ClassWizard will add and remove mapping macros here.
		//    DO NOT EDIT what you see in these blocks of generated code!
	//}}AFX_MSG_MAP
	// Standard file based document commands
	ON_COMMAND(ID_FILE_NEW, CWinApp::OnFileNew)
	ON_COMMAND(ID_FILE_OPEN, CWinApp::OnFileOpen)
	// Standard print setup command
	ON_COMMAND(ID_FILE_PRINT_SETUP, CWinApp::OnFilePrintSetup)
END_MESSAGE_MAP()

/
// CMyDrawApp construction

CMyDrawApp::CMyDrawApp()
{
	// TODO: add construction code here,
	// Place all significant initialization in InitInstance
}

/
// The one and only CMyDrawApp object

CMyDrawApp theApp;

/
// CMyDrawApp initialization

BOOL CMyDrawApp::InitInstance()
{
	// Standard initialization
	// If you are not using these features and wish to reduce the size
	//  of your final executable, you should remove from the following
	//  the specific initialization routines you do not need.

#ifdef _AFXDLL
	Enable3dControls();			// Call this when using MFC in a shared DLL
#else
	Enable3dControlsStatic();	// Call this when linking to MFC statically
#endif

	// Change the registry key under which our settings are stored.
	// TODO: You should modify this string to be something appropriate
	// such as the name of your company or organization.
	SetRegistryKey(_T("Local AppWizard-Generated Applications"));

	LoadStdProfileSettings();  // Load standard INI file options (including MRU)

	// Register the application's document templates.  Document templates
	//  serve as the connection between documents, frame windows and views.

	CSingleDocTemplate* pDocTemplate;
	pDocTemplate = new CSingleDocTemplate(
		IDR_MAINFRAME,
		RUNTIME_CLASS(CMyDrawDoc),
		RUNTIME_CLASS(CMainFrame),       // main SDI frame window
		RUNTIME_CLASS(CMyDrawView));
	AddDocTemplate(pDocTemplate);

	// Enable DDE Execute open
	EnableShellOpen();
	RegisterShellFileTypes(TRUE);

	// Parse command line for standard shell commands, DDE, file open
	CCommandLineInfo cmdInfo;
	ParseCommandLine(cmdInfo);

	// Dispatch commands specified on the command line
	if (!ProcessShellCommand(cmdInfo))
		return FALSE;

	// The one and only window has been initialized, so show and update it.
	m_pMainWnd->ShowWindow(SW_SHOW);
	m_pMainWnd->UpdateWindow();

	// Enable drag/drop open
	m_pMainWnd->DragAcceptFiles();

	return TRUE;
}


/
// CAboutDlg dialog used for App About

class CAboutDlg : public CDialog
{
public:
	CAboutDlg();

// Dialog Data
	//{{AFX_DATA(CAboutDlg)
	enum { IDD = IDD_ABOUTBOX };
	//}}AFX_DATA

	// ClassWizard generated virtual function overrides
	//{{AFX_VIRTUAL(CAboutDlg)
	protected:
	virtual void DoDataExchange(CDataExchange* pDX);    // DDX/DDV support
	//}}AFX_VIRTUAL

// Implementation
protected:
	//{{AFX_MSG(CAboutDlg)
		// No message handlers
	//}}AFX_MSG
	DECLARE_MESSAGE_MAP()
};

CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
	//{{AFX_DATA_INIT(CAboutDlg)
	//}}AFX_DATA_INIT
}

void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CAboutDlg)
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
	//{{AFX_MSG_MAP(CAboutDlg)
		// No message handlers
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

// App command to run the dialog
void CMyDrawApp::OnAppAbout()
{
	CAboutDlg aboutDlg;
	aboutDlg.DoModal();
}

/
// CMyDrawApp message handlers
// Shape.cpp: implementation of the CShape class.
//
//

#include "stdafx.h"
#include "MyDraw.h"
#include "Shape.h"
#include "Resource.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif

//
// Construction/Destruction
//


// Class CShape implementation

IMPLEMENT_SERIAL(CShape, CObject, 1)

CShape::CShape()
{
	m_boxShape.SetRect(0, 0, 0, 0);
    m_bTransparent = true;
    m_nColorShape = ID_COLOR_BLACK;
}

CShape::~CShape()
{

}



// Class CShpRectangle implementation

IMPLEMENT_SERIAL(CShpRectangle, CShape, 1)

void CShpRectangle::Draw(CDC* pDC)  // Virtual override
{
    pDC->Rectangle(m_boxShape);
}


// Class CShpEllipse implementation

IMPLEMENT_SERIAL(CShpEllipse, CShape, 1)

void CShpEllipse::Draw(CDC* pDC)  // Virtual override
{
    pDC->Ellipse(m_boxShape);
}
// DrawVw.cpp : implementation of the CMyDrawView class
//

#include "stdafx.h"

#include "MyDraw.h"
#include "DrawVw.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/
// CMyDrawView

IMPLEMENT_DYNCREATE(CMyDrawView, CView)

BEGIN_MESSAGE_MAP(CMyDrawView, CView)
	//{{AFX_MSG_MAP(CMyDrawView)
	ON_COMMAND(ID_TOOL_RECTANGLE, OnToolRectangle)
	ON_COMMAND(ID_TOOL_ELLIPSE, OnToolEllipse)
	ON_WM_LBUTTONDOWN()
	ON_WM_MOUSEMOVE()
	ON_WM_LBUTTONUP()
	ON_UPDATE_COMMAND_UI(ID_TOOL_RECTANGLE, OnUpdateToolRectangle)
	ON_UPDATE_COMMAND_UI(ID_TOOL_ELLIPSE, OnUpdateToolEllipse)
	ON_COMMAND(ID_TOOL_TRANSPARENT, OnToolTransparent)
	ON_UPDATE_COMMAND_UI(ID_TOOL_TRANSPARENT, OnUpdateToolTransparent)
	//}}AFX_MSG_MAP
	// Standard printing commands
	ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
	ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
	ON_COMMAND_RANGE(ID_COLOR_BLACK, ID_COLOR_LTGRAY, OnToolColor)
	ON_UPDATE_COMMAND_UI_RANGE(ID_COLOR_BLACK, ID_COLOR_LTGRAY, 
                                      OnUpdateToolColor)
END_MESSAGE_MAP()

/
// CMyDrawView construction/destruction

CMyDrawView::CMyDrawView()
{
	// TODO: add construction code here
	// Initialize random number generator for random bounding rects.
    m_typeNext = shpRectangle;
    m_bCaptured = false;
    m_pBrushOld = NULL;
    m_bTransparent = true;
	m_nColorNext = ID_COLOR_BLACK;
	m_pPenOld = NULL;
	m_pPenNew = NULL;

}

CMyDrawView::~CMyDrawView()
{
}

BOOL CMyDrawView::PreCreateWindow(CREATESTRUCT& cs)
{
	// TODO: Modify the Window class or styles here by modifying
	//  the CREATESTRUCT cs

	return CView::PreCreateWindow(cs);
}

/
// CMyDrawView drawing

void CMyDrawView::OnDraw(CDC* pDC)
{
    CMyDrawDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);

	// TODO: add draw code for native data here
    
	// Iterate the shapes from oldest to newest.
	// (Draw them in the same order as originally drawn).
	CShape* pShape;
	pDoc->SetToOldestShape();
	while(pDoc->GetPos() != NULL)
	{
		// Get the shape and use it to set the pen and brush.
		// Last shape sets position to NULL.
		pShape = pDoc->GetPrevShape();
		SetPenBrush(pDC, pShape->m_bTransparent, 
			pShape->m_nColorShape);
		// Ask the shape to draw itself.
		pShape->Draw(pDC);
		// Clean up.
		ResetPenBrush(pDC);
	}

}


/
// CMyDrawView printing

BOOL CMyDrawView::OnPreparePrinting(CPrintInfo* pInfo)
{
	// default preparation
	return DoPreparePrinting(pInfo);
}

void CMyDrawView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add extra initialization before printing
}

void CMyDrawView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
{
	// TODO: add cleanup after printing
}

/
// CMyDrawView diagnostics

#ifdef _DEBUG
void CMyDrawView::AssertValid() const
{
	CView::AssertValid();
}

void CMyDrawView::Dump(CDumpContext& dc) const
{
	CView::Dump(dc);
}

CMyDrawDoc* CMyDrawView::GetDocument() // non-debug version is inline
{
	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMyDrawDoc)));
	return (CMyDrawDoc*)m_pDocument;
}
#endif //_DEBUG

/
// CMyDrawView message handlers

void CMyDrawView::OnToolRectangle() 
{
	// TODO: Add your command handler code here
	m_typeNext = shpRectangle;
}

void CMyDrawView::OnToolEllipse() 
{
	// TODO: Add your command handler code here
	m_typeNext = shpEllipse;    
}

// Generate a random positive coordinate within a COORD_MAX- 
//  by COORD_MAX-unit drawing area.

void CMyDrawView::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	SetCapture();
    m_bCaptured = true;

    ASSERT(m_typeNext == shpRectangle || m_typeNext == 
		shpEllipse);

    CMyDrawDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    // Create CShape and add it to our list; return a ptr to it.
    m_pShpTemp = pDoc->CreateShape(m_typeNext);
    // Mark the document as changed.
    pDoc->SetModifiedFlag();

    // Start setting properties of the new shape.
	m_pShpTemp->m_bTransparent = m_bTransparent;
    m_pShpTemp->m_nColorShape = m_nColorNext;
    
    // Store starting point - literally a point, initially 
    //  (topLeft == botRight).
    m_pShpTemp->m_boxShape.left = 
		m_pShpTemp->m_boxShape.right = point.x;
    m_pShpTemp->m_boxShape.top = 
		m_pShpTemp->m_boxShape.bottom = point.y;

    CView::OnLButtonDown(nFlags, point);  

}

void CMyDrawView::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	if(m_bCaptured)
    {
        CClientDC dc(this);

        // Erase previous rectangle first.
        InvertShape(&dc, *m_pShpTemp);

        // Store new temporary corner as bottom right.
        m_pShpTemp->m_boxShape.bottom = point.y;
        m_pShpTemp->m_boxShape.right = point.x;

        // Draw new rectangle (latest rubberbanded rectangle).
        InvertShape(&dc, *m_pShpTemp);
    }

	CView::OnMouseMove(nFlags, point);
}

void CMyDrawView::OnLButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
if(m_bCaptured)
    {
        ::ReleaseCapture();
        m_bCaptured = false;

        CClientDC dc(this);

        // Erase previous rubberband rectangle.
        InvertShape(&dc, *m_pShpTemp);

        // Set the botRight corner's final values.
        m_pShpTemp->m_boxShape.right = point.x;
        m_pShpTemp->m_boxShape.bottom = point.y;
        
        // Draw final rectangle.
        InvertShape(&dc, *m_pShpTemp, false);  // Draw
           
    }

	CView::OnLButtonUp(nFlags, point);
}

void CMyDrawView::SetPenBrush(CDC *pDC, bool bTransparent, 
							  UINT nColor)
{
    ASSERT(pDC != NULL);
    // Make CShape's interior empty (transparent).
    if(bTransparent)
    {
        m_pBrushOld = (CBrush*)pDC->SelectStockObject(NULL_BRUSH);
    }
    else
    {
        m_pBrushOld = (CBrush*)pDC->SelectStockObject(WHITE_BRUSH);
    }
    ASSERT(m_pBrushOld != NULL);

	// Set up the pen
    ASSERT(nColor - ID_COLOR_BLACK >= 0 &&
           nColor - ID_COLOR_BLACK <= 
           (sizeof(arColors) / sizeof(arColors[0])));
    // Construct pen object on heap so we can clean it up after use
    m_pPenNew = new CPen();
    // Create the GDI pen & select it into the device context.
    m_pPenNew->CreatePen(PS_INSIDEFRAME, 0, 
                           arColors[nColor - ID_COLOR_BLACK]);
    m_pPenOld = (CPen*)pDC->SelectObject(m_pPenNew);

    // Device context restored in companion function 
	//  ResetPenBrush

}

void CMyDrawView::ResetPenBrush(CDC *pDC)
{
    ASSERT(pDC != NULL);
    // Restore previous pen and brush to device context after use.
    ASSERT(m_pBrushOld != NULL);
    pDC->SelectObject(m_pBrushOld);
	pDC->SelectObject(m_pPenOld);
    // Our responsibility to delete the heap object
    delete m_pPenNew;
    m_pPenNew = NULL;
    m_pPenOld = NULL;
    m_pBrushOld = NULL;
}

void CMyDrawView::InvertShape(CDC *pDC, CShape &s, bool bInvert)
{
    ASSERT(pDC != NULL);
    // Drawing mode is R2_NOT: black -> white, white -> black,
    //  colors -> inverse color.
    // If CShape already drawn, this erases; else draws it.
    int nModeOld;
    if(bInvert)
    {
        nModeOld = pDC->SetROP2(R2_NOT);
    }

    // Draw the CShape (or erase it).
    SetPenBrush(pDC, s.m_bTransparent, s.m_nColorShape);
    s.Draw(pDC);

    // Restore old values in DC.
    if(bInvert)
    {
        pDC->SetROP2(nModeOld);
    }
    ResetPenBrush(pDC);

}

void CMyDrawView::OnUpdateToolRectangle(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	pCmdUI->SetCheck(m_typeNext == shpRectangle);   
}

void CMyDrawView::OnUpdateToolEllipse(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	pCmdUI->SetCheck(m_typeNext == shpEllipse); 
}

void CMyDrawView::OnToolTransparent() 
{
	// TODO: Add your command handler code here
	m_bTransparent = !m_bTransparent;
}

void CMyDrawView::OnUpdateToolTransparent(CCmdUI* pCmdUI) 
{
	// TODO: Add your command update UI handler code here
	pCmdUI->SetCheck(m_bTransparent);
}

void CMyDrawView::OnToolColor(UINT nID)
{
    // Set the color for future CShape drawing
    m_nColorNext = nID;
}

void CMyDrawView::OnUpdateToolColor(CCmdUI* pCmdUI)
{
    // Check or uncheck all color menu items
    // Check item if it's the currently selected color
    // Uncheck all other colors
    pCmdUI->SetCheck(pCmdUI->m_nID == m_nColorNext);
}


  • 23
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值