Introduction to Charts

Introduction

A chart is a technique of representing numerical values using drawn shapes. For example, instead of using an evolution of something using a series of numbers, you can draw a line for each value. In the same way, instead of showing a distribution of fractional numbers using percentage values, you can draw a series of pies inside of a circle and draw each pie with different characteristics.

To draw a chart, you can use a series of rectangles, a circle divided in pies, or a polyline, etc. One of your first concerns would involve the numbers: what types of numbers would be involved and how do you want to represent them in a chart? This means that your second decision may consist on the type of chart you want.

As an introduction, in this exercise, we will draw a type that is commonly referred to column chart

Prerequisites:

  • Single Document Interface
  • Frames
  • Edit Control
  • Buttons
  • Dialog Bars

Practical Learning: Starting the Exercise

 
  1. Start Microsoft Visual C++
  2. Use MFC AppWizard to create a new project named ColumnChart
  3. Create the project as a Single Document and click Finish
  4. To add a dialog bar to the frame, display the Insert Resource (MSVC6: Insert -> Resource...) or Add Resource (MSVC .NET: Project -> Add Resource...)
     
  5. In the dialog box, expand the Dialog node and double-click IDD_DIALOGBAR
  6. Change its ID to IDD_CHART_BAR
  7. Design the dialog bar as follows:
     
     
    Control ID Caption Additional Properties
    Static Text Static Text   Monday  
    Edit Box Edit Box IDC_MONDAY   Align Text: Right
    Static Text Static Text   Tuesday  
    Edit Box Edit Box IDC_TUESDAY   Align Text: Right
    Static Text Static Text   Wednesday  
    Edit Box Edit Box IDC_WEDNESDAY   Align Text: Right
    Static Text Static Text   Thursday  
    Edit Box Edit Box IDC_THURSDAY   Align Text: Right
    Static Text Static Text   Friday  
    Edit Box Edit Box IDC_FRIDAY   Align Text: Right
    Button IDC_CHART_BTN Generate  
  8. Access the header file of main frame (MainFrm.h) and declare a public CDialogBar variable named m_wndChartBar:
     
    protected:  // control bar embedded members
    	CStatusBar  m_wndStatusBar;
    	CToolBar    m_wndToolBar;
    
    public:
    	CDialogBar  m_wndChartBar;
    
    // Generated message map functions
    protected:
    	//{{AFX_MSG(CMainFrame)
    	afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
    	afx_msg void OnViewChartbar();
    	//}}AFX_MSG
    	DECLARE_MESSAGE_MAP()
    };
  9. Access the menu. Under the View category, add a new item whose caption is Chart Bar and whose Checked property is set to true
     
  10. Using either the ClassWizard (MSVC6) or by right-clicking it, add an event or message to the menu item and associate it with the CMainFrame class
     
  11. Access the source file of main frame (MainFrm.cpp) to initialize the m_wndChartBar variable and display some sample values in its edit boxes. You will do this in the OnCreate() event. Based on this, change the source file as follows:
     
    // MainFrm.cpp : implementation of the CMainFrame class
    //
    
    #include "stdafx.h"
    #include "ColumnChart.h"
    
    #include "MainFrm.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    /////////////////////////////////////////////////////////////////////////////
    // CMainFrame
    
    IMPLEMENT_DYNCREATE(CMainFrame, CFrameWnd)
    
    BEGIN_MESSAGE_MAP(CMainFrame, CFrameWnd)
    	//{{AFX_MSG_MAP(CMainFrame)
    	ON_WM_CREATE()
    	ON_COMMAND(ID_VIEW_CHARTBAR, OnViewChartbar)
    	//}}AFX_MSG_MAP
    END_MESSAGE_MAP()
    
    static UINT indicators[] =
    {
    	ID_SEPARATOR,           // status line indicator
    	ID_INDICATOR_CAPS,
    	ID_INDICATOR_NUM,
    	ID_INDICATOR_SCRL,
    };
    
    /////////////////////////////////////////////////////////////////////////////
    // CMainFrame construction/destruction
    
    CMainFrame::CMainFrame()
    {
    	// TODO: add member initialization code here
    	
    }
    
    CMainFrame::~CMainFrame()
    {
    }
    
    int CMainFrame::OnCreate(LPCREATESTRUCT lpCreateStruct)
    {
    	if (CFrameWnd::OnCreate(lpCreateStruct) == -1)
    		return -1;
    	
    	if (!m_wndToolBar.CreateEx(this, TBSTYLE_FLAT, WS_CHILD | WS_VISIBLE | CBRS_TOP
    		| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC) ||
    		!m_wndToolBar.LoadToolBar(IDR_MAINFRAME))
    	{
    		TRACE0("Failed to create toolbar\n");
    		return -1;      // fail to create
    	}
    
    	// If the user undocks the Standard toolbar, display its name
    	this->m_wndToolBar.SetWindowText(_T("Standard"));
    
    	// Create the chart dialog bar
    	if( !m_wndChartBar.Create(this, IDD_CHART_BAR, TBSTYLE_FLAT | WS_CHILD | WS_VISIBLE | CBRS_TOP
    		| CBRS_GRIPPER | CBRS_TOOLTIPS | CBRS_FLYBY | CBRS_SIZE_DYNAMIC, IDD_CHART_BAR) )
    	{
    		TRACE0("Failed to create the chart bar\n");
    		return -1;      // fail to create
    	}
    	this->m_wndChartBar.SetWindowText(_T("Chart Bar"));
    
    	if (!m_wndStatusBar.Create(this) ||
    		!m_wndStatusBar.SetIndicators(indicators,
    		  sizeof(indicators)/sizeof(UINT)))
    	{
    		TRACE0("Failed to create status bar\n");
    		return -1;      // fail to create
    	}
    
    	// TODO: Delete these three lines if you don't want the toolbar to
    	//  be dockable
    	m_wndToolBar.EnableDocking(CBRS_ALIGN_ANY);
    	// Because of the presence of its edit boxes, allow the dialog bar
    	// to be positioned only to the top or to the bottom of the frame
    	m_wndChartBar.EnableDocking(CBRS_ALIGN_TOP | CBRS_ALIGN_BOTTOM);
    
    	EnableDocking(CBRS_ALIGN_ANY);
    
    	DockControlBar(&m_wndToolBar);
    	DockControlBar(&m_wndChartBar);
    
    	// Before performing an operation on the text boxes, get a pointer to each
    	CEdit *pEditMonday    = reinterpret_cast<CEdit *>(this->m_wndChartBar.GetDlgItem(IDC_MONDAY));
    	CEdit *pEditTuesday   = reinterpret_cast<CEdit *>(this->m_wndChartBar.GetDlgItem(IDC_TUESDAY));
    	CEdit *pEditWednesday = reinterpret_cast<CEdit *>(this->m_wndChartBar.GetDlgItem(IDC_WEDNESDAY));
    	CEdit *pEditThursday  = reinterpret_cast<CEdit *>(this->m_wndChartBar.GetDlgItem(IDC_THURSDAY));
    	CEdit *pEditFriday    = reinterpret_cast<CEdit *>(this->m_wndChartBar.GetDlgItem(IDC_FRIDAY));
    	
    	// Set some initial values in the edit boxes
    	pEditMonday->SetWindowText(_T("12000"));
    	pEditTuesday->SetWindowText(_T("11000"));
    	pEditWednesday->SetWindowText(_T("8500"));
    	pEditThursday->SetWindowText(_T("16800"));
    	pEditFriday->SetWindowText(_T("17500"));
    
    	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.style &= ~FWS_ADDTOTITLE;
    
    	cs.cx = 480;
    	cs.cy = 390;
    
    	return TRUE;
    }
    
    /////////////////////////////////////////////////////////////////////////////
    // CMainFrame diagnostics
    
    #ifdef _DEBUG
    void CMainFrame::AssertValid() const
    {
    	CFrameWnd::AssertValid();
    }
    
    void CMainFrame::Dump(CDumpContext& dc) const
    {
    	CFrameWnd::Dump(dc);
    }
    
    #endif //_DEBUG
    
    /////////////////////////////////////////////////////////////////////////////
    // CMainFrame message handlers
    
    
    void CMainFrame::OnViewChartbar() 
    {
    	// TODO: Add your command handler code here
    	CMenu *m_pMenu = this->GetMenu();
    
    	if(m_pMenu->GetMenuState(ID_VIEW_CHARTBAR, MF_CHECKED) )
    	{
    		ShowControlBar(&this->m_wndChartBar, FALSE, FALSE);
    		m_pMenu->CheckMenuItem(ID_VIEW_CHARTBAR, MF_UNCHECKED);
    	}
    	else
    	{
    		ShowControlBar(&this->m_wndChartBar, TRUE, TRUE);
    		m_pMenu->CheckMenuItem(ID_VIEW_CHARTBAR, MF_CHECKED);
    	}
    }
  12. Access the header file of the view class (ColumnChartView.h) and declare the following integer variables:
     
    protected:
    	int iMonday, iTuesday, iWednesday, iThursday, iFriday;
    
    // Generated message map functions
    protected:
    	//{{AFX_MSG(CChartsView)
    	afx_msg void OnChartBtn();
    	//}}AFX_MSG
    	DECLARE_MESSAGE_MAP()
    };
    
    #ifndef _DEBUG  // debug version in ChartsView.cpp
    inline CChartsDoc* CChartsView::GetDocument()
       { return (CChartsDoc*)m_pDocument; }
    #endif
    
    /////////////////////////////////////////////////////////////////////////////
  13. In MSVC6, display the dialog bar, right-click the button and click ClassWizard. When the Adding Class dialog box displays, click Cancel.
    In MSVC .NET, display the dialog bar, right-click the Generate button, and click Add Event Handler
  14. Associate a BN_CLICKED message to the to the view class:
     
  15. Click Edit Code and change the file as follows:
     
    // ColumnChartView.cpp : implementation of the CColumnChartView class
    //
    
    #include "stdafx.h"
    #include "ColumnChart.h"
    
    #include "ColumnChartDoc.h"
    #include "ColumnChartView.h"
    
    #include "MainFrm.h"
    
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif
    
    /////////////////////////////////////////////////////////////////////////////
    // CColumnChartView
    
    IMPLEMENT_DYNCREATE(CColumnChartView, CView)
    
    BEGIN_MESSAGE_MAP(CColumnChartView, CView)
    	//{{AFX_MSG_MAP(CColumnChartView)
    	ON_BN_CLICKED(IDC_CHART_BTN, OnChartBtn)
    	//}}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)
    END_MESSAGE_MAP()
    
    /////////////////////////////////////////////////////////////////////////////
    // CColumnChartView construction/destruction
    
    CColumnChartView::CColumnChartView()
    {
    	// TODO: add construction code here
    
    	iMonday    = 20;
    	iTuesday   = 20;
    	iWednesday = 20;
    	iThursday  = 20;
    	iFriday    = 20;
    }
    
    CColumnChartView::~CColumnChartView()
    {
    }
    
    BOOL CColumnChartView::PreCreateWindow(CREATESTRUCT& cs)
    {
    	// TODO: Modify the Window class or styles here by modifying
    	//  the CREATESTRUCT cs
    
    	return CView::PreCreateWindow(cs);
    }
    
    /////////////////////////////////////////////////////////////////////////////
    // CColumnChartView drawing
    
    void CColumnChartView::OnDraw(CDC* pDC)
    {
    	CColumnChartDoc* pDoc = GetDocument();
    	ASSERT_VALID(pDoc);
    	// TODO: add draw code for native data here
    	CBrush brsMonday(RGB(255, 0, 0)),
    		   brsTuesday(RGB(0, 255, 0)),
    		   brsWednesday(RGB(0, 0, 255)),
    		   brsThursday(RGB(255, 0, 255)),
    		   brsFriday(RGB(0, 128, 64));
    	CPen   penBlack1;
    
    	penBlack1.CreatePen(PS_SOLID, 1, RGB(0, 0, 0));
    	CPen *pOldPen = pDC->SelectObject(&penBlack1);
    
    	CRect rctClient;
    	this->GetClientRect(&rctClient);
    
    	CBrush *pOldBrush = pDC->SelectObject(&brsMonday);
    	
    	CRect rctMonday, rctTuesday, rctWednesday, rctThursday, rctFriday;
    
    	rctMonday.left   = rctClient.left + 20;
    	rctMonday.top    = rctClient.top  + 200 - iMonday;
    	rctMonday.right  = rctClient.left + 60;
    	rctMonday.bottom = rctClient.top  + 220;
    	pDC->Rectangle(rctMonday);
    
    	pOldBrush = pDC->SelectObject(&brsTuesday);
    	rctTuesday.left   = rctClient.left + 95;
    	rctTuesday.top    = rctClient.top  + 200 - iTuesday;
    	rctTuesday.right  = rctClient.left + 135;
    	rctTuesday.bottom = rctClient.top  + 220;
    	pDC->Rectangle(rctTuesday);
    	
    	pOldBrush = pDC->SelectObject(&brsWednesday);
    	rctWednesday.left   = rctClient.left + 170;
    	rctWednesday.top    = rctClient.top  + 200 - iWednesday;
    	rctWednesday.right  = rctClient.left + 210;
    	rctWednesday.bottom = rctClient.top  + 220;
    	pDC->Rectangle(rctWednesday);
    	
    	pOldBrush = pDC->SelectObject(&brsThursday);
    	rctThursday.left   = rctClient.left + 245;
    	rctThursday.top    = rctClient.top  + 200 -iThursday;
    	rctThursday.right  = rctClient.left + 285;
    	rctThursday.bottom = rctClient.top  + 220;
    	pDC->Rectangle(rctThursday);
    
    	pOldBrush = pDC->SelectObject(&brsFriday);
    	rctFriday.left   = rctClient.left + 320;
    	rctFriday.top    = rctClient.top  + 200 - iFriday;
    	rctFriday.right  = rctClient.left + 360;
    	rctFriday.bottom = rctClient.top  + 220;
    	pDC->Rectangle(rctFriday);
    
    	CPen   penBlack2;
    
    	penBlack2.CreatePen(PS_SOLID, 2, RGB(0, 0, 0));
    	pOldPen = pDC->SelectObject(&penBlack2);
    	pDC->MoveTo(rctClient.left+5, rctClient.top+220);
    	pDC->LineTo(rctClient.left+380, rctClient.top+220);
    
    	pDC->SelectObject(pOldBrush);
    	pDC->SelectObject(pOldPen);
    }
    
    /////////////////////////////////////////////////////////////////////////////
    // CColumnChartView printing
    
    BOOL CColumnChartView::OnPreparePrinting(CPrintInfo* pInfo)
    {
    	// default preparation
    	return DoPreparePrinting(pInfo);
    }
    
    void CColumnChartView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
    	// TODO: add extra initialization before printing
    }
    
    void CColumnChartView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
    	// TODO: add cleanup after printing
    }
    
    /////////////////////////////////////////////////////////////////////////////
    // CColumnChartView diagnostics
    
    #ifdef _DEBUG
    void CColumnChartView::AssertValid() const
    {
    	CView::AssertValid();
    }
    
    void CColumnChartView::Dump(CDumpContext& dc) const
    {
    	CView::Dump(dc);
    }
    
    CColumnChartDoc* CColumnChartView::GetDocument() // non-debug version is inline
    {
    	ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CColumnChartDoc)));
    	return (CColumnChartDoc*)m_pDocument;
    }
    #endif //_DEBUG
    
    /////////////////////////////////////////////////////////////////////////////
    // CColumnChartView message handlers
    
    void CColumnChartView::OnChartBtn() 
    {
    	// TODO: Add your control notification handler code here
    	
    	CMainFrame *cFrame    = reinterpret_cast<CMainFrame *>(AfxGetMainWnd());
    	CEdit *pEditMonday    = reinterpret_cast<CEdit *>(cFrame->m_wndChartBar.GetDlgItem(IDC_MONDAY));
    	CEdit *pEditTuesday   = reinterpret_cast<CEdit *>(cFrame->m_wndChartBar.GetDlgItem(IDC_TUESDAY));
    	CEdit *pEditWednesday = reinterpret_cast<CEdit *>(cFrame->m_wndChartBar.GetDlgItem(IDC_WEDNESDAY));
    	CEdit *pEditThursday  = reinterpret_cast<CEdit *>(cFrame->m_wndChartBar.GetDlgItem(IDC_THURSDAY));
    	CEdit *pEditFriday    = reinterpret_cast<CEdit *>(cFrame->m_wndChartBar.GetDlgItem(IDC_FRIDAY));
    
    	CString strMonday, strTuesday, strWednesday, strThursday, strFriday;
    	
    	pEditMonday->GetWindowText(strMonday);
    	pEditTuesday->GetWindowText(strTuesday);
    	pEditWednesday->GetWindowText(strWednesday);
    	pEditThursday->GetWindowText(strThursday);
    	pEditFriday->GetWindowText(strFriday);
    
    	this->iMonday    = atoi(strMonday) / 100;
    	this->iTuesday   = atoi(strTuesday) / 100;
    	this->iWednesday = atoi(strWednesday) / 100;
    	this->iThursday  = atoi(strThursday) / 100;
    	this->iFriday    = atoi(strFriday) / 100;
    
    	// Update the chart
    	this->Invalidate();
    }
  16. Test the application
     
  17. After using it, close it and return to your programming environment

Download

 
 

Home Copyright 2004 FunctionX, Inc.