Introduction to the View Classes |
|
Different applications have various ways to present their documents. To support these variances, the MFC provides different view-based classes. To lay a foundation for those classes,
the MFC provides a class named
CView. Although the MFC provides various view-based classes, it is likely that none of
them would fit the particular functionality you want to implement. For this reason, the
CView class accomplishes two purposes. Not only is it the ancestor to the other view-based classes, it is still a view in its own right and you can use it to create an application that none of the other classes can handle. For these two and other reasons, you should be quite familiar with the
CView class.
Creation of a CView-Based Application |
|
CView is an abstract class. In other words, you cannot just declare a CView variable. For example, the following code produces an error:
CView *view = new CView;
Therefore, to use CView, you must derive a class from it. What makes
CView a pure abstract class is that one of its methods is declared pure.
When deriving your class from CView, you must override a method named OnDraw. The syntax of the
CView::OnDraw() method is:
virtual void OnDraw(CDC* pDC) = 0;
Notice that it is declared pure (= 0).
Practical Learning: Introducing View-Based Applications
|
|
- If necessary, start Microsoft Visual C++. To create a new program, on the main menu, click File -> New Project…
- In the Templates list, click MFC Application
- Set the Name to GCS1 and click OK
- In the first page of the MFC Application Wizard, click Next
- In the right list, click Single Document and click Next twice
- In the File Extension edit box, type gcs
- In the Main Frame Caption text box, type Georgetown Cleaning Services
- Click Next three times
- Set the Number of Files On Recent File List to 8 and click Next
- Click Finish
- Click Class View and click CMainFrame
- Below the list of classes, double-click PreCreateWindow and make the following changes:
int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
return -1;
. . .
// TODO: Delete these three lines if
// you don't want the toolbar to be dockable
m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
EnableDocking(CBRS_ALIGN_ANY);
DockControlBar(&m_wndToolBar);
CenterWindow();
return 0;
}
BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs)
{
if( !CFrameWnd::PreCreateWindow(cs) )
return FALSE;
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
cs.cx = 550;
cs.cy = 630;
cs.style &= ~FWS_ADDTOTITLE;
return TRUE;
}
|
- On the main menu, click Project -> Add Resource…
- In the Add Resource dialog box, click Dialog and click New
- Using the Properties window, change the ID of the dialog box to IDB_CLEANINGORDER_DLG
- Right-click the dialog box and click Add Class…
- Set the Class Name to CCleaningOrderDlg
- Click Finish
- Design the dialog box as follows:
|
Control |
ID |
Caption |
Additional Properties |
Group Box |
|
|
Order Identification |
|
Static Text |
|
|
Customer Name: |
|
Edit Control |
|
IDC_CUSTOMERNAME |
|
|
Static Text |
|
|
Customer Phone: |
|
Edit Control |
|
IDC_CUSTOMERPHONE |
|
|
Static Text |
|
|
Date Left: |
|
Date Time Picker |
|
IDC_DATELEFT |
|
|
Static Text |
|
|
Time Left: |
|
Date Time Picker |
|
IDC_TIMELEFT |
|
|
Static Text |
|
|
Date Expected: |
|
Date Time Picker |
|
IDC_DATEEXPECTED |
|
|
Static Text |
|
|
Time Expected: |
|
Date Time Picker |
|
IDC_TIMEEXPECTED |
|
|
Group Box |
|
|
Order Processing |
|
Static Text |
|
|
Item Type |
|
Static Text |
|
|
Unit Price |
|
Static Text |
|
|
Qty |
|
Static Text |
|
|
Sub Total |
|
Static Text |
|
|
Shirts |
|
Edit Control |
|
IDC_SHIRTS_UNITPRICE |
|
Align Text: Right |
Edit Control |
|
IDC_SHIRTS_QTY |
|
Align Text: Right
Number: True |
Edit Control |
|
IDC_SHIRTS_SUBTOTAL |
|
Align Text: Right |
Static Text |
|
|
Pants |
|
Edit Control |
|
IDC_PANTS_UNITPRICE |
|
Align Text: Right |
Edit Control |
|
IDC_PANTS_QTY |
|
Align Text: Right
Number: True |
Edit Control |
|
IDC_PANTS_SUBTOTAL |
|
Align Text: Right |
ComboBox |
|
IDC_ITEM1NAME |
|
Data: None;Women Suit;Dress;Regular Skirt;Skirt With Hook;Men 's Suit 2Pc;Men 's Suit 3Pc;Sweaters;Silk Shirt;Tie;Coat;Jacket;Swede; |
Edit Control |
|
IDC_ITEM1UNITPRICE |
|
Align Text: Right |
Edit Control |
|
IDC_ITEM1QUANTITY |
|
Align Text: Right
Number: True |
Edit Control |
|
IDC_ITEM1SUBTOTAL |
|
Align Text: Right |
ComboBox |
|
IDC_ITEM2NAME |
|
Data: None;Women Suit;Dress;Regular Skirt;Skirt With Hook;Men 's Suit 2Pc;Men 's Suit 3Pc;Sweaters;Silk
Shirt;Tie;Coat;Jacket;Swede; |
Edit Control |
|
IDC_ITEM2UNITPRICE |
|
Align Text: Right |
Edit Control |
|
IDC_ITEM2QUANTITY |
|
Align Text: Right
Number: True |
Edit Control |
|
IDC_ITEM2SUBTOTAL |
|
Align Text: Right |
ComboBox |
|
IDC_ITEM3NAME |
|
Data: None;Women Suit;Dress;Regular Skirt;Skirt With Hook;Men 's Suit 2Pc;Men 's Suit 3Pc;Sweaters;Silk
Shirt;Tie;Coat;Jacket;Swede; |
Edit Control |
|
IDC_ITEM3UNITPRICE |
|
Align Text: Right |
Edit Control |
|
IDC_ITEM3QUANTITY |
|
Align Text: Right
Number: True |
Edit Control |
|
IDC_SUBTOTAL3 |
|
Align Text: Right |
ComboBox |
|
IDC_ITEM4NAME |
|
Data: None;Women Suit;Dress;Regular Skirt;Skirt With Hook;Men 's Suit 2Pc;Men 's Suit 3Pc;Sweaters;Silk
Shirt;Tie;Coat;Jacket;Swede; |
Edit Control |
|
IDC_ITEM4UNITPRICE |
|
Align Text: Right |
Edit Control |
|
IDC_ITEM4QUANTITY |
|
Align Text: Right
Number: True |
Edit Control |
|
IDC_ITEM4SUBTOTAL |
|
Align Text: Right |
Group Box |
|
|
Order Summary |
|
Static Text |
|
|
Cleaning Total: |
|
Edit Control |
|
IDC_CLEANINGTOTAL |
|
Align Text: Right |
Static Text |
|
|
Tax Rate: |
|
Edit Control |
|
IDC_TAXRATE |
|
Align Text: Right |
Static Text |
|
|
% |
|
Static Text |
|
|
Tax Amount: |
|
Edit Control |
|
IDC_TAXAMOUNT |
|
Align Text: Right |
Static Text |
|
|
Order Price: |
|
Edit Control |
|
IDC_ORDERTOTAL |
|
Align Text: Right |
Button |
|
IDOK |
OK/Submit |
|
Button |
|
IDC_RESET |
Reset |
|
Button |
|
IDCCANCEL |
Cancel/Close |
|
|
- Right-click each control and click Add Variable
- Add the control variables as follows:
Identifier |
Value Variable |
Type |
Name |
IDC_CUSTOMERNAME |
CString |
m_CustomerName |
IDC_CUSTOMERPHONE |
CString |
m_CustomerPhone |
IDC_DATELEFT |
CTime |
m_DateLeft |
IDC_TIMELEFT |
CTime |
m_TimeLeft |
IDC_DATEEXPECTED |
CTime |
m_DateExpected |
IDC_TIMEEXPECTED |
CTime |
m_TimeExpected |
IDC_SHIRTS_UNITPRICE |
double |
m_ShirtsUnitPrice |
IDC_SHIRTS_QTY |
int |
m_ShirtsQuantity |
IDC_SHIRTS_SUBTOTAL |
CString |
m_ShirtsSubTotal |
IDC_PANTS_UNITPRICE |
double |
m_PantsUnitPrice |
IDC_PANTS_QTY |
int |
m_PantsQuantity |
IDC_PANTS_SUBTOTAL |
CString |
m_PantsSubTotal |
IDC_ITEM1NAME |
CString |
m_Item1Name |
IDC_ITEM1UNITPRICE |
double |
m_Item1UnitPrice1 |
IDC_ITEM1QUANTITY |
int |
m_Item1Quantity1 |
IDC_ITEM1SUBTOTAL |
CString |
m_Item1SubTotal1 |
IDC_ITEM2NAME |
CString |
m_Item2Name |
IDC_ITEM2UNITPRICE |
double |
m_Item2UnitPrice |
IDC_ITEM2QUANTITY |
int |
m_Item2Quantity |
IDC_ITEM2SUBTOTAL |
CString |
m_Item2SubTotal |
IDC_ITEM3NAME |
CString |
m_Item3Name |
IDC_ITEM3UNITPRICE |
double |
m_Item3UnitPrice |
IDC_ITEM3QUANTITY |
int |
m_Item3Quantity |
IDC_ITEM3SUBTOTAL |
CString |
m_Item3SubTotal |
IDC_ITEM4NAME |
CString |
m_Item4Name |
IDC_ITEM4UNITPRICE |
double |
m_Item4UnitPrice |
IDC_ITEM4QUANTITY |
int |
m_Item4Quantity |
IDC_ITEM4SUBTOTAL |
CString |
m_Item4SubTotal |
IDC_CLEANINGTOTAL |
CString |
m_CleaningTotal |
IDC_TAXRATE |
double |
m_TaxRate |
IDC_TAXAMOUNT |
CString |
m_TaxAmount |
IDC_ORDERTOTAL |
CString |
m_OrderTotal |
- In the Class View, double-click CCleaningOrderDlg to access the dialog box’ header file and declare a
CString variable for each Date Time Picker control as follows:
#pragma once
// CCleaningOrderDlg dialog
class CCleaningOrderDlg : public CDialog
{
DECLARE_DYNAMIC(CCleaningOrderDlg)
public:
CCleaningOrderDlg(CWnd* pParent = NULL); // standard constructor
virtual ~CCleaningOrderDlg();
// Dialog Data
enum { IDD = IDB_CLEANINGORDER_DLG };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
DECLARE_MESSAGE_MAP()
CString m_CustomerName;
CString m_CustomerPhone;
CTime m_DateLeft;
CTime m_TimeLeft;
CTime m_DateExpected;
CTime m_TimeExpected;
CString strDateLeft;
CString strTimeLeft;
CString strDateExpected;
CString strTimeExpected;
double m_ShirtsUnitPrice;
int m_ShirtsQuantity;
CString m_ShirtsSubTotal;
double m_PantsUnitPrice;
int m_PantsQuantity;
CString m_PantsSubTotal;
CString m_Item1Name;
double m_Item1UnitPrice;
int m_Item1Quantity;
CString m_Item1SubTotal;
CString m_Item2Name;
double m_Item2UnitPrice;
int m_Item2Quantity;
CString m_Item2SubTotal;
CString m_Item3Name;
double m_Item3UnitPrice;
int m_Item3Quantity;
CString m_Item3SubTotal;
CString m_Item4Name;
double m_Item4UnitPrice;
int m_Item4Quantity;
CString m_Item4SubTotal;
CString m_CleaningTotal;
double m_TaxRate;
CString m_TaxAmount;
CString m_OrderTotal;
};
|
- In the Class View, click CCleaningOrderDlg and, below the list of classes, double-click CCleacningOderDlg to access its constructor and change it as follows:
CCleaningOrderDlg::CCleaningOrderDlg(CWnd* pParent /*=NULL*/)
: CDialog(CCleaningOrderDlg::IDD, pParent)
, m_CustomerName(_T(""))
, m_CustomerPhone(_T(""))
, m_DateLeft(CTime::GetCurrentTime())
, m_TimeLeft(CTime::GetCurrentTime())
, m_DateExpected(CTime::GetCurrentTime())
, m_TimeExpected(CTime::GetCurrentTime())
, m_ShirtsUnitPrice(0.95)
, m_ShirtsQuantity(0)
, m_ShirtsSubTotal(_T("0.00"))
, m_PantsUnitPrice(1.75)
, m_PantsQuantity(0)
, m_PantsSubTotal(_T("0.00"))
, m_Item1Name(_T(""))
, m_Item1UnitPrice(0)
, m_Item1Quantity(0)
, m_Item1SubTotal(_T("0.00"))
, m_Item2Name(_T(""))
, m_Item2UnitPrice(0)
, m_Item2Quantity(0)
, m_Item2SubTotal(_T("0.00"))
, m_Item3Name(_T(""))
, m_Item3UnitPrice(0)
, m_Item3Quantity(0)
, m_Item3SubTotal(_T("0.00"))
, m_Item4Name(_T(""))
, m_Item4UnitPrice(0)
, m_Item4Quantity(0)
, m_Item4SubTotal(_T("0.00"))
, m_CleaningTotal(_T("0.00"))
, m_TaxRate(7.75)
, m_TaxAmount(_T("0.00"))
, m_OrderTotal(_T("0.00"))
{
}
|
- In the Class View, click CCleaningOrderDlg
- In the Properties window, click the Overrides button and generate the OnInitDialog event
- Add the following code to it:
BOOL CCleaningOrderDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// TODO: Add extra initialization here
m_DateLeft.Format = TEXT("dddd dd MMM yyyy");
m_DateExpected.Format = TEXT("dddd dd MMM yyyy");
return TRUE; // return TRUE unless you set the focus to a control
// EXCEPTION: OCX Property Pages should return FALSE
}
|
- Display the dialog box and double-click the Reset Cleaning Order button to implement it as follows:
void CCleaningOrderDlg::OnBnClickedReset()
{
// TODO: Add your control notification handler code here
m_CustomerName = _T("");
m_CustomerPhone = _T("");
m_DateLeft = CTime::GetCurrentTime();
m_TimeLeft = CTime::GetCurrentTime();
m_DateExpected = CTime::GetCurrentTime();
m_TimeExpected = CTime::GetCurrentTime();
m_ShirtsUnitPrice = 0.95;
m_ShirtsQuantity = 0;
m_ShirtsSubTotal = _T("0.00");
m_PantsUnitPrice = 1.75;
m_PantsQuantity = 0;
m_PantsSubTotal = _T("0.00");
m_Item1Name = _T("");
m_Item1UnitPrice = 0;
m_Item1Quantity = 0;
m_Item1SubTotal = _T("0.00");
m_Item2Name = _T("");
m_Item2UnitPrice = 0;
m_Item2Quantity = 0;
m_Item2SubTotal = _T("0.00");
m_Item3Name = _T("");
m_Item3UnitPrice = 0;
m_Item3Quantity = 0;
m_Item3SubTotal = _T("0.00");
m_Item4Name = _T("");
m_Item4UnitPrice = 0;
m_Item4Quantity = 0;
m_Item4SubTotal = _T("0.00");
m_CleaningTotal = _T("0.00");
m_TaxRate = 7.75;
m_TaxAmount = _T("0.00");
m_OrderTotal = _T("0.00");
UpdateData(FALSE);
}
|
- In the Class View, right-click CCleaningOrderDlg -> Add -> Add Function…
- Set the Return Type to void, the Function Name to CalculateOrder, and and the Access to private
- Click Finish and implement the method as follows:
void CCleaningOrderDlg::CalculateOrder(void)
{
UpdateData();
double subTotalShirts = m_ShirtsUnitPrice * m_ShirtsQuantity;
m_ShirtsSubTotal.Format(TEXT("%.2f"), subTotalShirts);
double subTotalPants = m_PantsUnitPrice * m_PantsQuantity;
m_PantsSubTotal.Format(TEXT("%.2f"), subTotalPants);
double subTotalItem1;
if( (m_Item1Name == TEXT("None")) || (m_Item1Name == TEXT("")) )
subTotalItem1 = 0;
else
subTotalItem1 = m_Item1UnitPrice * m_Item1Quantity;
m_Item1SubTotal.Format(TEXT("%.2f"), subTotalItem1);
double subTotalItem2;
if( (m_Item2Name == TEXT("None")) || (m_Item2Name == TEXT("")) )
subTotalItem2 = 0;
else
subTotalItem2 = m_Item2UnitPrice * m_Item2Quantity;
m_Item2SubTotal.Format(TEXT("%.2f"), subTotalItem2);
double subTotalItem3;
if( (m_Item3Name == TEXT("None")) || (m_Item3Name == TEXT("")) )
subTotalItem3 = 0;
else
subTotalItem3 = m_Item3UnitPrice * m_Item3Quantity;
this->m_Item3SubTotal.Format(TEXT("%.2f"), subTotalItem3);
double subTotalItem4;
if( (m_Item4Name == TEXT("None")) || (m_Item4Name == TEXT("")) )
subTotalItem4 = 0;
else
subTotalItem4 = m_Item4UnitPrice * m_Item4Quantity;
m_Item4SubTotal.Format(TEXT("%.2f"), subTotalItem4);
double cleaningTotal = subTotalShirts + subTotalPants + subTotalItem1 +
subTotalItem2 + subTotalItem3 + subTotalItem4;
// Calculate the amount owed for the taxes
double taxAmount = cleaningTotal * m_TaxRate / 100;
// Add the tax amount to the cleaning total
double netPrice = cleaningTotal + taxAmount;
// Display the values of the order summary
this->m_CleaningTotal.Format(TEXT("%.2f"), cleaningTotal);
this->m_TaxAmount.Format(TEXT("%.2f"), taxAmount);
this->m_OrderTotal.Format(TEXT("%.2f"), netPrice);
strDateLeft = m_DateLeft.Format(TEXT("%A %d %b %Y"));
strTimeLeft = m_TimeLeft.Format(TEXT("%H:%M"));
strDateExpected = m_DateExpected.Format(TEXT("%A %d %b %Y"));
strTimeExpected = m_TimeExpected.Format(TEXT("%H:%M"));
UpdateData(FALSE);
}
|
- Display the dialog box and double-click the Time Left control
- Implement its Chantge event as follows:
void CCleaningOrderDlg::OnDtnDatetimechangeTimeleft(NMHDR *pNMHDR,
LRESULT *pResult)
{
LPNMDATETIMECHANGE pDTChange =
reinterpret_cast<LPNMDATETIMECHANGE>(pNMHDR);
// TODO: Add your control notification handler code here
*pResult = 0;
UpdateData();
CTime dateLeft, timeLeft;
dateLeft = m_DateLeft;
timeLeft = m_TimeLeft;
CTime time9AM = CTime(timeLeft.GetYear(), timeLeft.GetMonth(),
imeLeft.GetDay(), 9, 0, 0);
// If the customer leaves clothes before 9AM...
if( timeLeft <= time9AM )
{
// ... then they should be ready the same day after 5PM
m_DateExpected = dateLeft;
CTime tm5PM = CTime(dateLeft.GetYear(),
dateLeft.GetMonth(), dateLeft.GetDay(), 17, 0, 0);
m_TimeExpected = tm5PM;
}
else
{
// If the clothes were left after 9AM, they will be
// available the following day by 8AM
CTime tmTomorrowMorning = CTime(dateLeft.GetYear(),
dateLeft.GetMonth(), dateLeft.GetDay() + 1, 8, 0, 0);
m_DateExpected = tmTomorrowMorning;
m_TimeExpected = tmTomorrowMorning;
}
UpdateData(FALSE);
}
|
- Display the dialog box and click the Shirts Qty edit control
- In the Properties window, click the Contrl Events button, and generate an event for the EN_KILLFOCUS message
- Return to the dialog box and generate an event for the EN_KILLFOCUS message of all Qty edit controls
- Also, generate an event for the EN_KILLFOCUS message of the Tax Rate edit control
- In each event, simply call the CalculateOrder method:
void CCleaningOrderDlg::OnEnKillfocusShirtsQty()
{
// TODO: Add your control notification handler code here
CalculateOrder();
}
void CCleaningOrderDlg::OnEnKillfocusPantsQty()
{
// TODO: Add your control notification handler code here
CalculateOrder();
}
void CCleaningOrderDlg::OnEnKillfocusItem1quantity()
{
// TODO: Add your control notification handler code here
CalculateOrder();
}
void CCleaningOrderDlg::OnEnKillfocusItem2quantity()
{
// TODO: Add your control notification handler code here
CalculateOrder();
}
void CCleaningOrderDlg::OnEnKillfocusItem3quantity()
{
// TODO: Add your control notification handler code here
CalculateOrder();
}
void CCleaningOrderDlg::OnEnKillfocusItem4quantity()
{
// TODO: Add your control notification handler code here
CalculateOrder();
}
void CCleaningOrderDlg::OnEnKillfocusTaxrate()
{
// TODO: Add your control notification handler code here
CalculateOrder();
}
|
- Save all
Fundamental Implementation of a View |
|
If you don't want to write all of your primary code manually, you can use the MFC Application wizard that would create a skeleton functional application for you: it would derive a class from CView, would override the
OnDraw() event, and would perform many cosmetic initializations for you.
The basic view displays as a rectangular box with a white background delimited on all four sides by a frame, sometimes assisted by its resources such as a toolbar and/or a status bar. What you can do with this white area can be as vague or complex as you want.
When an application is launched, it first draws the frame and (some of) its resources, if any. Then, a document is invoked to prepare what to display to the user. This document is transmitted to the view that is in charge of displaying or drawing it. Before the view actually “shows” the document, you may want to prepare it. To assist you with this, the
CView class is equipped with the OnInitialUpdate() method (or
event). Its syntax is:
virtual void OnInitialUpdate();
As you can see, this method takes no argument. For most CView-based applications, you will hardly need to implement this event. In fact, if you create your
CView-based application using the MFC Application wizard, it would not generate the
OnInitialUpdate event for you. This is because it assumes that you are likely not going to need this event.
The OnInitialUpdate event is mostly useful to the CView-derived classes as we will see in
other sections.
Practical Learning: Implementing a View
|
|
- In the Class View, double-click the view node and declare the following variables in the header file:
// GCS1View.h : interface of the CGCS1View class
//
#pragma once
class CGCS1View : public CView
{
protected: // create from serialization only
CGCS1View();
DECLARE_DYNCREATE(CGCS1View)
// Attributes
public:
CGCS1Doc* GetDocument() const;
// Operations
public:
// 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 ~CGCS1View();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
DECLARE_MESSAGE_MAP()
private:
CString CustomerName;
CString CustomerPhone;
CString DateLeft;
CString TimeLeft;
CString DateExpected;
CString strTimeExpected;
CString ShirtsUnitPrice;
CString ShirtsQuantity;
CString ShirtsSubTotal;
CString PantsUnitPrice;
CString PantsQuantity;
CString PantsSubTotal;
CString Item1Name;
CString Item1UnitPrice;
CString Item1Quantity;
CString Item1SubTotal;
CString Item2Name;
CString Item2UnitPrice;
CString Item2Quantity;
CString Item2SubTotal;
CString Item3Name;
CString Item3UnitPrice;
CString Item3Quantity;
CString Item3SubTotal;
CString Item4Name;
CString Item4UnitPrice;
CString Item4Quantity;
CString Item4SubTotal;
CString CleaningTotal;
CString TaxRate;
CString TaxAmount;
CString OrderTotal;
};
#ifndef _DEBUG // debug version in GCS1View.cpp
inline CGCS1Doc* CGCS1View::GetDocument() const
{ return reinterpret_cast<CGCS1Doc*>(m_pDocument); }
#endif
|
- Display the IDR_MAINFRAME menu
- Change the caption (but not the ID) of the first menu item under file to
&New Cleaning Order\tCtrl+N
- Right-click this menu item and click Add Event Handler
- In the Event Handler Wizard, make sure hat COMMAND is selected in the Message Type list. In the Class List, click the view class
- Change the Function Handler Name to OnNewCleaningOrder
- Click Add and Edit
- In the top section of the file, include the header file of the Cleaning Order dialog box
// GCS1View.cpp : implementation of the CGCS1View class
//
#include "stdafx.h"
#include "GCS1.h"
#include "GCS1Doc.h"
#include "GCS1View.h"
#include "CleaningOrderDlg.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
|
- Edit the event as follows:
void CGCS1View::OnNewCleaningOrder()
{
// TODO: Add your command handler code here
CCleaningOrderDlg dlg;
dlg.m_DateLeft = CTime::GetCurrentTime();
dlg.m_TimeLeft = CTime::GetCurrentTime();
dlg.m_DateExpected = CTime::GetCurrentTime();
dlg.m_TimeExpected = CTime::GetCurrentTime();
if( dlg.DoModal() == IDOK )
{
CustomerName = dlg.m_CustomerName;
CustomerPhone = dlg.m_CustomerPhone;
DateLeft = dlg.strDateLeft;
TimeLeft = dlg.strTimeLeft;
DateExpected = dlg.strDateExpected;
TimeExpected = dlg.strTimeExpected;
ShirtsUnitPrice.Format(TEXT("%.2f"), dlg.m_ShirtsUnitPrice);
ShirtsQuantity.Format(TEXT("%d"), dlg.m_ShirtsQuantity);
ShirtsSubTotal = dlg.m_ShirtsSubTotal;
PantsUnitPrice.Format(TEXT("%.2f"), dlg.m_PantsUnitPrice);
PantsQuantity.Format(TEXT("%d"), dlg.m_PantsQuantity);
PantsSubTotal = dlg.m_PantsSubTotal;
Item1Name = dlg.m_Item1Name;
Item1UnitPrice.Format(TEXT("%.2f"), dlg.m_Item1UnitPrice);
Item1Quantity.Format(TEXT("%d"), dlg.m_Item1Quantity);
Item1SubTotal = dlg.m_Item1SubTotal;
Item2Name = dlg.m_Item2Name;
Item2UnitPrice.Format(TEXT("%.2f"), dlg.m_Item2UnitPrice);
Item2Quantity.Format(TEXT("%d"), dlg.m_Item2Quantity);
Item2SubTotal = dlg.m_Item2SubTotal;
Item3Name = dlg.m_Item3Name;
Item3UnitPrice.Format(TEXT("%.2f"), dlg.m_Item3UnitPrice);
Item3Quantity.Format(TEXT("%d"), dlg.m_Item3Quantity);
Item3SubTotal = dlg.m_Item3SubTotal;
Item4Name = dlg.m_Item4Name;
Item4UnitPrice.Format(TEXT("%.2f"), dlg.m_Item4UnitPrice);
Item4Quantity.Format(TEXT("%d"), dlg.m_Item4Quantity);
Item4SubTotal = dlg.m_Item4SubTotal;
CleaningTotal = dlg.m_CleaningTotal;
TaxRate.Format(TEXT("%.2f"), dlg.m_TaxRate);
TaxAmount = dlg.m_TaxAmount;
OrderTotal = dlg.m_OrderTotal;
Invalidate();
}
}
|
- Save all
Most of the time, a CView object is used to draw something on the document. To make this possible, the
CView class is equipped with the OnDraw() and we mentioned that you must always override it.
Practical Learning: Drawing a View
|
|
- In the Class View, click CGCS1View and double-click OnDraw
- Change the event as follows:
void CGCS1View::OnDraw(CDC* pDC)
{
CGCS1Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
CFont fntMainTitle, fntSubTitle,
fntSectTitle, fntLabel, fntResult;
int left = 15, top = 10;
TEXTMETRIC tm;
CPen penLine2, penLine1;
CBrush brsGray;
VERIFY(fntMainTitle.CreateFont(40, 0, 0, 0, FW_BOLD,
FALSE, FALSE, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH | FF_SWISS,
TEXT("Times New Roman")));
CFont *fntDefault = pDC->SelectObject(&fntMainTitle);
pDC->GetTextMetrics(&tm);
pDC->SetTextColor(RGB(0, 0, 0));
pDC->SetBkMode(TRANSPARENT);
pDC->SetTextCharacterExtra(1);
pDC->TextOut(left, top, TEXT("Georgetown Cleaning Services"));
top = top + tm.tmHeight;
pDC->SetTextCharacterExtra(4);
VERIFY(fntSubTitle.CreateFont(32, 0, 0, 0, FW_BOLD,
FALSE, FALSE, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH | FF_SWISS,
TEXT("Times New Roman")));
fntDefault = pDC->SelectObject(&fntSubTitle);
pDC->TextOut(140, top, TEXT("Cleaning Order"));
penLine2.CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
CPen *penOld = pDC->SelectObject(&penLine2);
pDC->MoveTo(10, tm.tmHeight + 50);
pDC->LineTo(515, tm.tmHeight + 50);
VERIFY(fntSectTitle.CreateFont(14, 0, 0, 0, FW_BOLD,
FALSE, FALSE, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH | FF_SWISS,
TEXT("Verdana")));
penLine1.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
penOld = pDC->SelectObject(&penLine1);
pDC->Rectangle(20, 120, 520, 210);
pDC->Rectangle(20, 230, 520, 400);
pDC->Rectangle(20, 420, 520, 520);
brsGray.CreateSolidBrush(RGB(128, 128, 128));
CBrush *oldBrush = pDC->SelectObject(&brsGray);
pDC->Rectangle(30, 110, 270, 130);
pDC->Rectangle(30, 220, 270, 240);
pDC->Rectangle(30, 410, 270, 430);
pDC->SetTextCharacterExtra(0);
fntDefault = pDC->SelectObject(&fntSectTitle);
pDC->SetTextColor(RGB(255, 255, 255));
pDC->TextOut(40, 112, TEXT("Order Identification"));
pDC->TextOut(40, 222, TEXT("Order Processing"));
pDC->TextOut(40, 412, TEXT("Order Summary"));
pDC->SetTextColor(RGB(0, 0, 0));
VERIFY(fntLabel.CreateFont(16, 0, 0, 0, FW_BOLD,
FALSE, FALSE, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH | FF_SWISS,
TEXT("Times New Roman")));
VERIFY(fntResult.CreateFont(16, 0, 0, 0, FW_NORMAL,
FALSE, FALSE, 0, ANSI_CHARSET,
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH | FF_SWISS,
TEXT("Times New Roman")));
fntDefault = pDC->SelectObject(&fntLabel);
pDC->TextOut(40, 140, TEXT("Customer Name: "));
fntDefault = pDC->SelectObject(&fntResult);
pDC->TextOut(150, 140, this->CustomerName);
fntDefault = pDC->SelectObject(&fntLabel);
pDC->TextOut(300, 140, TEXT("Customer Phone: "));
fntDefault = pDC->SelectObject(&fntResult);
pDC->TextOut(420, 140, this->CustomerPhone);
pDC->MoveTo(30, 155);
pDC->LineTo(510, 155);
fntDefault = pDC->SelectObject(&fntLabel);
pDC->TextOut(40, 160, TEXT("Date Left: "));
fntDefault = pDC->SelectObject(&fntResult);
pDC->TextOut(150, 160, this->DateLeft);
fntDefault = pDC->SelectObject(&fntLabel);
pDC->TextOut(300, 160, TEXT("Time Left: "));
fntDefault = pDC->SelectObject(&fntResult);
pDC->TextOut(420, 160, this->TimeLeft);
pDC->MoveTo(30, 175);
pDC->LineTo(510, 175);
fntDefault = pDC->SelectObject(&fntLabel);
pDC->TextOut(40, 180, TEXT("Date Expected: "));
fntDefault = pDC->SelectObject(&fntResult);
pDC->TextOut(150, 180, this->DateExpected);
fntDefault = pDC->SelectObject(&fntLabel);
pDC->TextOut(300, 180, TEXT("Time Expected: "));
fntDefault = pDC->SelectObject(&fntResult);
pDC->TextOut(420, 180, this->TimeExpected);
pDC->MoveTo(30, 195);
pDC->LineTo(510, 195);
fntDefault = pDC->SelectObject(&fntLabel);
pDC->TextOut( 40, 250, TEXT("Item Type"));
pDC->TextOut(320, 250, TEXT("Unit Price"));
pDC->TextOut(400, 250, TEXT("Qty"));
pDC->TextOut(445, 250, TEXT("Sub-Total"));
pDC->MoveTo( 30, 265);
pDC->LineTo(510, 265);
pDC->TextOut( 40, 270, TEXT("Shirts"));
fntDefault = pDC->SelectObject(&fntResult);
pDC->SetTextAlign(TA_RIGHT);
pDC->TextOut(365, 270, ShirtsUnitPrice);
pDC->TextOut(420, 270, ShirtsQuantity);
pDC->TextOut(495, 270, ShirtsSubTotal);
pDC->MoveTo( 30, 285);
pDC->LineTo(510, 285);
pDC->SetTextAlign(TA_LEFT);
fntDefault = pDC->SelectObject(&fntLabel);
pDC->TextOut( 40, 290, TEXT("Pants"));
pDC->SetTextAlign(TA_RIGHT);
fntDefault = pDC->SelectObject(&fntResult);
pDC->TextOut(365, 290, PantsUnitPrice);
pDC->TextOut(420, 290, PantsQuantity);
pDC->TextOut(495, 290, PantsSubTotal);
pDC->MoveTo( 30, 305);
pDC->LineTo(510, 305);
fntDefault = pDC->SelectObject(&fntLabel);
pDC->SetTextAlign(TA_LEFT);
pDC->TextOut( 40, 310, Item1Name);
fntDefault = pDC->SelectObject(&fntResult);
pDC->SetTextAlign(TA_RIGHT);
pDC->TextOut(365, 310, Item1UnitPrice);
pDC->TextOut(420, 310, Item1Quantity);
pDC->TextOut(495, 310, Item1SubTotal);
pDC->MoveTo(30, 325);
pDC->LineTo(510, 325);
pDC->SetTextAlign(TA_LEFT);
fntDefault = pDC->SelectObject(&fntLabel);
pDC->TextOut( 40, 330, Item2Name);
fntDefault = pDC->SelectObject(&fntResult);
pDC->SetTextAlign(TA_RIGHT);
pDC->TextOut(365, 330, Item2UnitPrice);
pDC->TextOut(420, 330, Item2Quantity);
pDC->TextOut(495, 330, Item2SubTotal);
pDC->MoveTo( 30, 345);
pDC->LineTo(510, 345);
pDC->SetTextAlign(TA_LEFT);
fntDefault = pDC->SelectObject(&fntLabel);
pDC->TextOut( 40, 350, Item3Name);
fntDefault = pDC->SelectObject(&fntResult);
pDC->SetTextAlign(TA_RIGHT);
pDC->TextOut(365, 350, Item3UnitPrice);
pDC->TextOut(420, 350, Item3Quantity);
pDC->TextOut(495, 350, Item3SubTotal);
pDC->MoveTo( 30, 365);
pDC->LineTo(510, 365);
pDC->SetTextAlign(TA_LEFT);
fntDefault = pDC->SelectObject(&fntLabel);
pDC->TextOut( 40, 370, Item4Name);
fntDefault = pDC->SelectObject(&fntResult);
pDC->SetTextAlign(TA_RIGHT);
pDC->TextOut(365, 370, Item4UnitPrice);
pDC->TextOut(420, 370, Item4Quantity);
pDC->TextOut(495, 370, Item4SubTotal);
pDC->MoveTo( 30, 385);
pDC->LineTo(510, 385);
pDC->SetTextAlign(TA_LEFT);
fntDefault = pDC->SelectObject(&fntLabel);
pDC->TextOut(300, 430, TEXT("Cleaning Total: "));
fntDefault = pDC->SelectObject(&fntResult);
pDC->SetTextAlign(TA_RIGHT);
pDC->TextOut(470, 430, CleaningTotal);
pDC->MoveTo(290, 445);
pDC->LineTo(510, 445);
pDC->SetTextAlign(TA_LEFT);
fntDefault = pDC->SelectObject(&fntLabel);
pDC->TextOut(300, 450, TEXT("Tax Rate: "));
fntDefault = pDC->SelectObject(&fntResult);
pDC->SetTextAlign(TA_RIGHT);
pDC->TextOut(470, 450, TaxRate + TEXT(" %"));
pDC->MoveTo(290, 465);
pDC->LineTo(510, 465);
pDC->SetTextAlign(TA_LEFT);
fntDefault = pDC->SelectObject(&fntLabel);
pDC->TextOut(300, 470, TEXT("Tax Amount: "));
fntDefault = pDC->SelectObject(&fntResult);
pDC->SetTextAlign(TA_RIGHT);
pDC->TextOut(470, 470, TaxAmount);
pDC->MoveTo(290, 485);
pDC->LineTo(510, 485);
pDC->SetTextAlign(TA_LEFT);
fntDefault = pDC->SelectObject(&fntLabel);
pDC->TextOut(300, 490, TEXT("Order Total: "));
fntDefault = pDC->SelectObject(&fntResult);
pDC->SetTextAlign(TA_RIGHT);
pDC->TextOut(470, 490, OrderTotal);
pDC->MoveTo(290, 505);
pDC->LineTo(510, 505);
pDC->SelectObject(fntDefault);
pDC->SelectObject(penOld);
}
|
- Execute the application and try processing an order by clicking File ->
New Cleaning Order
- After creating an order, click OK
- Close the application
|
|