- To start this exercise, create an MFC Application named Trajectory1
- Create it as a Single Document type
- To fill the window's content with a black background, access the source
file of the view and change its OnDraw event as follows:
void CTrajectory1View::OnDraw(CDC* pDC)
{
CTrajectory1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
CBrush brsBlack;
CRect rctClient;
brsBlack.CreateSolidBrush(RGB(0, 0, 0));
GetWindowRect(&rctClient);
CBrush *pOldBrush = pDC->SelectObject(&brsBlack);
pDC->Rectangle(0, 0, rctClient.Width(), rctClient.Height());
pDC->SelectObject(pOldBrush);
}
|
- Execute the application to see the result
The primary implementation of using a trajectory consist of
moving an object or a shape along a path. To do this, you can draw the shape in
response to a timer.
Practical Learning: Moving a Shape
|
|
- Using the Resource Symbols dialog box, create an ID
named IDT_MOVE
- Generate the OnInitialUpdate event for the view class and use it to
initialize the timer as follows:
void CTrajectory1View::OnInitialUpdate()
{
CView::OnInitialUpdate();
SetTimer(IDT_MOVE, 10, NULL);
// TODO: Add your specialized code here and/or call the base class
}
|
- In the view header file, declare the following variables:
// Trajectory1View.h : interface of the CTrajectory1View class
//
#pragma once
class CTrajectory1View : public CView
{
protected: // create from serialization only
CTrajectory1View();
DECLARE_DYNCREATE(CTrajectory1View)
// Attributes
public:
CTrajectory1Doc* GetDocument() const;
// Operations
public:
static const int ShapeWidth = 45;
static const int ShapeHeight = 15;
int x;
int y;
bool MovingRight;
// Overrides
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);
// Implementation
public:
virtual ~CTrajectory1View();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
DECLARE_MESSAGE_MAP()
};
#ifndef _DEBUG // debug version in Trajectory1View.cpp
inline CTrajectory1Doc* CTrajectory1View::GetDocument() const
{ return reinterpret_cast<CTrajectory1Doc*>(m_pDocument); }
#endif
|
- In the constructor of the view class, initialize the variables as
follows:
CTrajectory1View::CTrajectory1View()
{
// TODO: add construction code here
x = 0;
y = 200;
MovingRight = false;
}
|
- Change the OnDraw event as follows:
void CTrajectory1View::OnDraw(CDC* pDC)
{
CTrajectory1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
CPen penYellow;
CBrush brsBlack, brsFuchsia;
CRect rctClient;
brsBlack.CreateSolidBrush(RGB(0, 0, 0));
brsFuchsia.CreateSolidBrush(RGB(255, 0, 255));
penYellow.CreatePen(PS_SOLID, 1, RGB(255, 255, 0));
GetWindowRect(&rctClient);
CBrush *pOldBrush = pDC->SelectObject(&brsBlack);
pDC->Rectangle(0, 0, rctClient.Width(), rctClient.Height());
pOldBrush = pDC->SelectObject(&brsFuchsia);
CPen *pOldPen = pDC->SelectObject(&penYellow);
pDC->RoundRect(this->x, this->y, this->x + ShapeWidth,
this->y + ShapeHeight, 5, 5);
pDC->SelectObject(pOldPen);
pDC->SelectObject(pOldBrush);
}
|
- Generate the event of the WM_TIMER message for the view class and
implement it as follows:
void CTrajectory1View::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
CRect rctClient;
GetWindowRect(&rctClient);
if( this->x < 0 )
{
this->x = 0;
this->MovingRight = true;
}
if( this->x > rctClient.Width() - ShapeWidth )
{
this->x = rctClient.Width() - ShapeWidth;
this->MovingRight = FALSE;
}
if( x < 0 )
{
x = 0;
MovingRight = TRUE;
}
if( x > rctClient.Width() - ShapeWidth )
{
x = rctClient.Width() - ShapeWidth;
MovingRight = FALSE;
}
Invalidate();
if( MovingRight == TRUE )
x++;
else
x--;
CView::OnTimer(nIDEvent);
}
|
- Generate the event of the WM_ERASEBKGND message of the view class
and change its return value as follows:
BOOL CTrajectory1View::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
return TRUE; // CView::OnEraseBkgnd(pDC);
}
|
- Execute the application to see the result:
- Close it and return to MSVC
Object oriented programming consists of creating objects
that each can perform a specific task and take of assignments related to it. In
trajectory-related programming, you can create a class for each object or shape.
This can make it easy to recognize and use the object. If you happen to use
different objects, you can then customize the behavior of each.
Practical Learning: Creating a Shape Class
|
|
- To create a new class, on the main menu, click Project -> Add Class...
- In the Templates list, click C++ Class and click Add
- Set the Class Name to CShape and press Enter
- Change the header file as follows:
#pragma once
class CShape
{
public:
CShape(void);
public:
~CShape(void);
static const int Width = 45;
static const int Height = 15;
int x;
int y;
bool MovingRight;
void Draw(CDC* pDC);
void Move(CRect rctClient);
};
|
- Change the source file as follows:
#include "StdAfx.h"
#include "Shape.h"
CShape::CShape(void)
: x(0),
y(150),
MovingRight(false)
{
}
CShape::~CShape(void)
{
}
void CShape::Draw(CDC* pDC)
{
CPen penYellow;
CBrush brsFuchsia;
brsFuchsia.CreateSolidBrush(RGB(255, 0, 255));
penYellow.CreatePen(PS_SOLID, 1, RGB(255, 255, 0));
CBrush *pOldBrush = pDC->SelectObject(&brsFuchsia);
CPen *pOldPen = pDC->SelectObject(&penYellow);
pDC->RoundRect(this->x,
this->y,
this->x + CShape::Width,
this->y + CShape::Height,
5,
5);
pDC->SelectObject(pOldBrush);
}
void CShape::Move(CRect rctClient)
{
if( this->x < 0 )
{
this->x = 0;
this->MovingRight = true;
}
if( this->x > rctClient.Width() - CShape::Width )
{
this->x = rctClient.Width() - CShape::Width;
this->MovingRight = FALSE;
}
}
|
- Access the header file of the view class and change it as follows:
// Trajectory2View.h : interface of the CTrajectory1View class
//
#pragma once
#include "Shape.h"
class CTrajectory1View : public CView
{
protected: // create from serialization only
CTrajectory1View();
DECLARE_DYNCREATE(CTrajectory1View)
// Attributes
public:
CTrajectory1Doc* GetDocument() const;
// Operations
public:
CShape *shape;
// Overrides
public:
. . .
};
#ifndef _DEBUG // debug version in Trajectory2View.cpp
inline CTrajectory1Doc* CTrajectory1View::GetDocument() const
{ return reinterpret_cast<CTrajectory1Doc*>(m_pDocument); }
#endif
|
- Access the source file of the view class and change it as follows:
// Trajectory2View.cpp : implementation of the CTrajectory1View class
//
#include "stdafx.h"
#include "Trajectory2.h"
#include "Trajectory2Doc.h"
#include "Trajectory2View.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CTrajectory1View
IMPLEMENT_DYNCREATE(CTrajectory1View, CView)
BEGIN_MESSAGE_MAP(CTrajectory1View, CView)
// 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_WM_TIMER()
ON_WM_ERASEBKGND()
END_MESSAGE_MAP()
// CTrajectory1View construction/destruction
CTrajectory1View::CTrajectory1View()
{
// TODO: add construction code here
shape = new CShape;
}
CTrajectory1View::~CTrajectory1View()
{
delete shape;
}
BOOL CTrajectory1View::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CView::PreCreateWindow(cs);
}
// CTrajectory1View drawing
void CTrajectory1View::OnDraw(CDC* pDC)
{
CTrajectory1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
CPen penYellow;
CBrush brsBlack, brsFuchsia;
CRect rctClient;
brsBlack.CreateSolidBrush(RGB(0, 0, 0));
brsFuchsia.CreateSolidBrush(RGB(255, 0, 255));
penYellow.CreatePen(PS_SOLID, 1, RGB(255, 255, 0));
GetWindowRect(&rctClient);
CBrush *pOldBrush = pDC->SelectObject(&brsBlack);
pDC->Rectangle(0, 0, rctClient.Width(), rctClient.Height());
shape->Draw(pDC);
pDC->SelectObject(pOldBrush);
}
. . .
// CTrajectory1View message handlers
void CTrajectory1View::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
CRect rctClient;
GetWindowRect(&rctClient);
shape->Move(rctClient);
Invalidate();
if( shape->MovingRight == TRUE )
shape->x++;
else
shape->x--;
CView::OnTimer(nIDEvent);
}
void CTrajectory1View::OnInitialUpdate()
{
CView::OnInitialUpdate();
SetTimer(IDT_MOVE, 10, NULL);
// TODO: Add your specialized code here and/or call the base class
}
BOOL CTrajectory1View::OnEraseBkgnd(CDC* pDC)
{
// TODO: Add your message handler code here and/or call default
return TRUE; // CView::OnEraseBkgnd(pDC);
}
|
- Execute the application and notice that it produces the same result
|
|