概念
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 onm ouseMove(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);
}
标签:void,多态,C++,step,AFX,CMyDrawDoc,CShape,CMyDrawView,pDC
From: https://blog.csdn.net/workflower/article/details/140168251