Lab 5: Enhancing the STUpload Data Display

In Lab 3, you learned how to implement a very simple OnDraw() function for the STUpload application, which outputs the data records held in the application document object as lines of text. The application displays all the records that are stored in the document—currently a hard-coded set of records representing data from three different stock funds.

In Lab 5, you are going to enhance the application in two ways. First, you are going to implement the Select Fund dialog box, a modeless dialog box that allows the user to select from a list of funds currently stored in the application document object. Then you will create a new CSTUploadView::OnDraw() function to display data for the currently selected fund in a graph format.

Displaying the Select Fund Dialog Box

To create the Select Fund dialog box, you will use the dialog template IDD_ FUNDDIALOG and the class CFundDialog that you created for Lab 4. At this point, the dialog box design is not complete. The final version will not have OK and Cancel buttons because you are going to allow the user to show and hide the dialog box using only the Select Fund command option on the View menu (or by using the toolbar button). However, you will need to overload the OnOK() and OnCancel() handler functions. Because IDOK and IDCANCEL messages will be generated when the user presses the ENTER or ESC keys, you will need to create versions of the handler functions for the Select Fund dialog class that do nothing; otherwise, the base class (CDialog) versions will be called. Remember that the base class versions call the EndDialog() function to dismiss the dialog box.

It is much easier to add handlers for the OK and Cancel messages when the buttons are still defined as part of the dialog box, so you will create OnOK() and OnCancel() handlers at this point.

  • To create the OnOk() handler
    1. Press CTRL+W to open ClassWizard. In the Class name box, click CFundDialog.
    2. In the Object IDs box, click IDOK.
    3. In the Messages box, click BN_CLICKED.
    4. Click Add Function and then click OK to accept the suggested handler name OnOK.
    5. Click Edit Code to jump to the CFundDialog::OnOK() implementation code.
    6. From the body of this function remove the following line:
    7. CDialog::OnOK();

    8. Repeat the process to add an empty OnCancel() function to handle the BN_CLICKED message for the IDCANCEL item. Now you can remove the OK and Cancel buttons from the dialog template.

  • To complete the Select Fund dialog template
    1. Open the IDD_FUNDDIALOG resource with the dialog editor.
    2. Click OK. Press the DELETE key to remove the button.
    3. Click Cancel. Press DELETE.
    4. Resize the dialog box so the list box fits just inside the dashed blue edit guide. Your dialog box should look as shown in Figure 5.20.
    5. Figure 5.20 The Select Fund dialog box

    Now you will write code to control the behavior of the Select Fund dialog box. You will create a single CFundDialog object early on in the application, as the m_wndFundDialog member of the application main frame window object CMainFrame. The dialog window will be a child window of the application main window, and it will be shown or hidden according to the status of m_bFundsVisible, a Boolean member variable of the CMainFrame class. The status of m_bFundsVisible will be set by menu and toolbar commands.

  • To create the m_wndFundDialog member object
    1. In ClassView, right-click the CMainFrame class icon.
    2. On the shortcut menu, click Add Member Variable.
    3. In the Add Member Variable dialog box, type CFundDialog into the Variable Type box.
    4. Type m_wndFundDialog in the Variable Name box.
    5. Set the access specifier to Protected. Click OK to add the variable.
    6. Repeat the process to add a protected BOOL member variable m_bFundsVisible to the CMainFrame class.
    7. Double-click the CMainFrame class icon in ClassView to open the header file and jump to the top of the class declaration.
    8. Check that ClassView has added the following line of code to the top of the file:
    9. #include "FundDialog.h"

  • To initialize the m_bFundsVisible member in the class constructor
    1. Double-click the icon that represents the CMainFrame class constructor.
    2. Add the following line of code to the body of the function:
    3. m_bFundsVisible = FALSE;

  • To create accessor functions for the m_bFundsVisible member variable
    1. Return to the CMainFrame class declaration in MainFrm.h. Add the following lines of code to the public section:
    2. (This code can be found in CH5_01.cpp, installed from the companion CD.)

      BOOL AreFundsVisible() {return m_bFundsVisible;} void SetFundsVisible(BOOL bSet)  {      m_bFundsVisible = bSet;      if(bSet) m_wndFundDialog.ShowWindow(SW_SHOW);      else m_wndFundDialog.ShowWindow(SW_HIDE); }

    3. You will now need to initialize your dialog object by calling its Create() function and passing the resource ID as a parameter. The Create() function takes a second parameter with which you can specify the dialog box's parent window. You will use the default setting NULL, which sets the parent window to be the main application window.

  • To initialize the m_wndFundDialog object
    1. In ClassView, expand the CMainFrame class icon.
    2. Double-click the OnCreate() member function icon to jump to the function implementation.
    3. At the end of the function, before the return statement, add the following lines of code:
    4. // Create the fund dialog window m_wndFundDialog.Create(IDD_FUNDDIALOG);

    Remember that the dialog box does not have the WS_VISIBLE style property, so it will need to be displayed explicitly with a call to the CWnd::ShowWindow() function.

    Hiding and showing the dialog box is going to be controlled by the handler for the Selection Fund command on the View menu. In the following exercises, you will create a command handler and a user interface update command handler for the ID_VIEW_FUNDSELECTION command ID.

  • To add the CMainFrame::OnViewFundselection() function
    1. Press CTRL+W to invoke ClassWizard. Click the Message Maps tab.
    2. In the Class Name box, click CMainFrame.
    3. In the Object IDs box, click ID_VIEW_FUNDSELECTION.
    4. In the Messages box, click COMMAND.
    5. Click Add Function. Click OK to accept the suggested handler function name OnViewFundselection().
    6. Click Edit Code. The MainFrm.cpp file is opened. and the insertion point is positioned at the top of the function implementation.
    7. Add the following line to the body of the OnViewFundselection() function:
    8. SetFundsVisible(m_bFundsVisible ? FALSE : TRUE);

  • To implement the CMainFrame::OnUpdateViewFundselection() function
    1. Using ClassWizard, create the OnUpdateViewFundselection function for the UPDATE_COMMAND_UI message and the ID_VIEW_ FUNDSELECTION object ID.
    2. Select Settings from the Project menu. On the C/C++ page, click C++ Language in the Category box. Ensure that Enable Run-Time Type Information (RTTI) is selected. Click OK to close the Project Settings dialog box.
    3. Add the following lines of code to the body of the function OnUpdateViewFundselection():
    4. (This code can be found in CH5_02.cpp, installed from the companion CD.)

      // Enable the View Funds Selection dialog if  // the document CStockDataList is not empty. // If enabled, then toggle button state checked/unchecked // according to whether the window is displayed or hidden BOOL bEnable = FALSE; CSTUploadDoc * pDoc =       dynamic_cast<CSTUploadDoc *>(GetActiveDocument()); if(pDoc)      bEnable = pDoc->GetDocList().GetCount() ? TRUE : FALSE; pCmdUI->Enable(bEnable);      if(bEnable)      pCmdUI->SetCheck(m_bFundsVisible ? 1 : 0);     

    5. Add the following line of code to the top of the MainFrm.cpp file:
    6. #include "STUploadDoc.h"

    7. You can now build and run the STUpload application. Experiment with showing and hiding the Select Fund dialog box by using the command and the toolbar button.

    Displaying Fund Names in the Funds List Box

    Now that you have displayed the Select Fund dialog box, you will write a function to load the names of the funds into the list box control. Because the list of fund records held in the CSTUploadDoc::m_DocList object will be created in fund sort order, it is not a difficult matter to iterate across the list and extract a unique list of fund names.

    Before you can write this function, you will have to create a variable with the MFC type CListBox.

  • To add the CFundDialog::m_listBox member variable
    1. Press CTRL+W to open ClassWizard and click the Member Variables tab.
    2. In the Class Name list, click the CFundDialog class.
    3. Click Add Variable. In the Member variable name box, type m_listBox.
    4. In the Category box, click Control. The Variable Type box displays CListBox.
    5. Click OK to create the variable, and then click OK again to close ClassWizard.

    You are now going to add the UpdateFundList() member function to the CMainFrame class to perform the task of loading the fund name items into the list box. The function will take two parameters—a reference to a CStockDataList, which will be the source of the fund names; and a string to specify the fund name that should be selected initially. If the second parameter contains an empty string (the default value), or the provided string is not found in the list box, no item is selected.

  • To implement the CMainFrame::UpdateFundList() function
    1. In FileView, expand the Header Files folder and double-click the CMainFrm.h file icon to open the file.
    2. At the top of the file, with the other #include statements, add the following line:
    3. #include "StockDataList.h"

    4. Switch to ClassView and right-click the CMainFrame icon. Use the Add Member Function option to add the function declaration to the public section of the class declaration, and to add a function stub. The function should have the following signature:
    5. void UpdateFundList(const CStockDataList & pList,       CString strCurrentFund = "");

    6. Add the following code to the body of the UpdateFundList() function:
    7. (This code can be found in CH5_03.cpp, installed from the companion CD.)

      // Function to add one entry per fund to fund view list box. // CStockDataLists are sorted by fund name so this is easy. CListBox *pListBox = &m_wndFundDialog.m_listBox; // Empty current contents of list box pListBox->ResetContent(); CString strLastFund; POSITION pos = pList.GetHeadPosition(); while(pos) {      CStockData sd = pList.GetNext(pos);      CString strFund = sd.GetFund();      if(strFund != strLastFund)           pListBox->AddString(strFund);      strLastFund = strFund; } // Set list box selection to strCurrentFund parameter. // No selection if parameter empty or not found. int iPos = pListBox->FindStringExact(-1, strCurrentFund); pListBox->SetCurSel(iPos);

    Look through the code and make sure that you understand how the function achieves its objectives.

    The UpdateFundList() function will be called from the LoadData() function. Eventually the LoadData() function will handle the loading of data records from a text file. For now, you will create a temporary version that simply adds some hard-coded records.

  • To implement the STUploadDoc::LoadData() function
    1. Right-click the STUploadDoc icon in ClassView and use the Add Member Function dialog box to add the function declaration to the protected section of the class declaration, and to add a function stub. The function should have the following signature:
    2. BOOL LoadData(CStdioFile & infile)

    3. To the body of the LoadData() function, add the code from CH5_04.cpp (installed from the companion CD), part of which is shown below:
    4. m_DocList.AddTail(CStockData(_T("ARSC"),  COleDateTime(1999, 4, 1, 0, 0, 0), 22.33)); // ... more records added here m_DocList.AddTail(CStockData(_T("COMP"),  COleDateTime(1999, 4, 5, 0, 0, 0), 19.77)); // Update main window UpdateAllViews(NULL); // Update Fund Selection dialog box CMainFrame * pWnd =       dynamic_cast<CMainFrame *> (AfxGetMainWnd()); if(pWnd) {      pWnd->UpdateFundList(m_DocList);      // Show fund window after loading new funds      pWnd->SetFundsVisible(TRUE); } return TRUE;

    5. Add the following to the top of the CSTUploadDoc.cpp file:
    6. #include "MainFrm.h"

    7. Locate the CSTUploadDoc constructor. Remove all the implementation code to leave an empty function stub so that the constructor appears as follows:
    8. CSTUploadDoc::CSTUploadDoc() { }

    9. Locate the CSTUploadDoc::OnDataImport() function. To the bottom of the function, before the closing brace, add the following code to call the LoadData() function:
    10. if(nID == IDOK) {      CStdioFile aFile;      LoadData(aFile); }

    You can now build the STUpload application. Choose Import from the Data menu. Using the Open dialog box, open the Ch5Test.dat file from the ..\Chapter 5\Data folder. Records should be displayed for the ARSC, BBIC and COMP funds, and the Select Fund dialog box should display these three funds.

    Handling Notification Messages from the Select Fund Dialog Box

    The purpose of the Select Fund dialog box is to allow the user to limit the display of fund price data so that records for only the currently selected fund are displayed. You have already filled the list box with options—you now have to act upon the user's selection.

    To start, you will add the m_strCurrentFund variable to record the fund name currently selected by the user. In the next chapter, you will be making this variable persistent so that you can save the current user selection as part of the document data. Thus the m_strCurrentFund variable will be a member of the CSTUploadDoc class.

    To ensure that this variable always represents the current selection of the Select Fund dialog box, you will handle notification messages from the list box control. The list box sends a LBN_SELCHANGE message to its parent window (the CFundDialog object) every time the selection changes. You can use ClassWizard to provide a handler for this message.

    You will also change the CSTUploadView::OnDraw() function so that it refers to the "currently selected fund" variable held by the document object to ensure that it displays records that pertain to the currently selected fund only.

  • To add the CDocument::m_strCurrentFund member
  • Right-click the CDocument icon in ClassView and add a protected member variable of type CString named m_strCurrentFund.

  • To initialize the m_strCurrentFund member in the class constructor
    1. Double-click the icon that represents the CSTUploadDoc class constructor.
    2. Add the following line of code to the body of the function:
    3. m_strCurrentFund = "";

  • To create accessor functions for the m_strCurrentFund member variable
  • Add the following lines of code to the public section of the CDocument class declaration:

    CString GetCurrentFund () {return m_strCurrentFund;} void SetCurrentFund (CString strSet){m_strCurrentFund= strSet;}

  • To add a method to the CFundDialog class to handle the LBN_SELCHANGE message
    1. Press CTRL+W to open ClassWizard. Click the Message Maps tab.
    2. In the Class Name box, click CFundDialog.
    3. In the Object IDs box, click IDC_FUNDLIST.
    4. In the Messages box, click LBN_SELCHANGE.
    5. Click Add Function. Click OK to accept the suggested handler function name OnSelchangeFundlist().
    6. Click Edit Code. The FundDialog.cpp file is opened and the insertion point is positioned at the top of the function implementation.

  • To implement the CMainFrame::OnSelchangeFundlist() function
    1. Add the following lines of code to the body of the OnSelchangeFundlist() function:
    2. (This code can be found in CH5_05.cpp, installed from the companion CD.)

      CMainFrame * pWnd =       dynamic_cast<CMainFrame *> (AfxGetMainWnd()); ASSERT_VALID(pWnd); CSTUploadDoc * pDoc =       dynamic_cast<CSTUploadDoc *>(pWnd->GetActiveDocument()); ASSERT_VALID(pDoc); CString strCurFund; int sel = m_listBox.GetCurSel(); if(sel == LB_ERR) sel = 0; m_listBox.GetText(sel, strCurFund); pDoc->SetCurrentFund(strCurFund); pDoc->UpdateAllViews(NULL);

    3. Add the following lines of code to the top of the FundDialog.cpp file:
    4. #include "MainFrm.h" #include "STUploadDoc.h"

  • To alter the CSTUploadView::OnDraw() function
    1. Locate the display loop at the bottom of the CSTUploadView::OnDraw() function. Just after the call to CStockDataList::GetNext(), add this code:
    2. if(sd.GetFund() != pDoc->GetCurrentFund()) continue;

      The entire loop section should now look as follows:

      while(pos) {      CStockData sd = pData.GetNext(pos);      if(sd.GetFund() != pDoc->GetCurrentFund())continue;      pDC->TextOut(10, yPos, sd.GetAsString());      yPos += nTextHeight; }

    3. Build and run the STUpload application. Test loading the data as before. You will now see that no records appear initially, but as soon as you select a fund from the Select Fund dialog box, the appropriate records will appear.

    Making the Select Fund Dialog Box a Topmost Window

    The Select Fund dialog box is a key element of the STUpload application user interface. It will be constantly in use to switch from fund to fund as the operator checks through the data held on file. In its current implementation, however, it is easily hidden if the user clicks on the main application window—to access the main menu, for example. The Select Fund dialog box is so small that it is inconvenient to retrieve once it is hidden behind the larger window.

    The solution to this problem is to make the Select Fund dialog box a topmost window—that is, a window that is always on top of other windows in the application. A topmost window will appear even if it does not have input focus.

    A topmost window has the style WS_EX_TOPMOST. In an MFC application, you can set this by calling the CWnd::SetWindowPos() function with the address of the wndTopMost constant as the first parameter.

  • To set the Select Fund dialog box as a topmost window
    1. In ClassView, double-click the CMainFrame::OnCreate() function icon to edit the code.
    2. At the bottom of the function, directly after the following line:
    3. m_wndFundDialog.Create(IDD_FUNDDIALOG);

      and before the return statement, add the line shown below.

      m_wndFundDialog.SetWindowPos(&wndTopMost, 0, 0, 0, 0,       SWP_NOMOVE | SWP_NOSIZE);

    This is all you need to do to make the Select Fund dialog box stay on top of the application main window. Unfortunately, it has the undesirable side effect of making the dialog box stay on top of all other application windows—even when the STUpload application is not active. If you build and run the application and test its behavior at this point, you will see that the Select Fund dialog box remains visible even when the STUpload application is minimized.

    To solve this problem, you need to hide the dialog box (if it is visible) at the point where the application as a whole loses focus, and then re-display it when the user switches focus back to the application. To do this, you need to provide a handler for the WM_ACTIVATEAPP message, which is called when the user switches between applications. You will use ClassWizard to create a handler that is an overload of the CWnd::OnActivateApp() method. This function is called by the framework with a Boolean parameter that indicates whether the application is being activated or deactivated.

  • To add a handler for the WM_ACTIVATEAPP message
    1. Press CTRL+W to open ClassWizard. Click the Message Maps tab.
    2. In the Class Name box, click CMainFrame.
    3. In the Object IDs box, click CMainFrame.
    4. In the Messages box, click WM_ACTIVATEAPP.
    5. Click Add Function.
    6. Click Edit Code. The MainFrm.cpp file is opened, and the insertion point is positioned at the top of the function implementation.

  • To implement the CMainFrame::OnActivateApp() function
    1. To the body of the OnActivateApp() function, after the call to the base-class version, add the following code:
    2. (This code can be found in CH5_15.cpp, installed from the companion CD.)

      if(bActive) {      if(AreFundsVisible())            m_wndFundDialog.ShowWindow(SW_SHOW); } else {      if(AreFundsVisible())            m_wndFundDialog.ShowWindow(SW_HIDE); }

    3. Build the application and test to ensure that the Select Fund dialog box remains on top of the STUpload application window, but that it is hidden when other applications have focus.

    Displaying STUpload Application Data

    You are now ready to implement the graphical display of price data for the currently selected fund. The first task is to determine the document size so that the scroll bars provided by CScrollView will appear correctly. In the STUpload application, although the size of the application data changes as text files are loaded into the document, the size of the display output remains constant. Only one graph is displayed at any time. You will fix the size of the graph to the size of a standard laser printer page in landscape orientation—that is, 11 inches wide by 8.5 inches tall.

  • To set up scroll sizes for the STUpload application
    1. In ClassView, expand the CSTUploadView class icon.
    2. Double click the OnInitialUpdate() icon to edit the function.
    3. Edit the following lines:
    4. sizeTotal.cx = sizeTotal.cy = 100; SetScrollSizes(MM_TEXT, sizeTotal);

      so that they appear as follows:

      sizeTotal.cx = 1100; sizeTotal.cy = 850; SetScrollSizes(MM_LOENGLISH, sizeTotal);

    You will now replace the CView::OnDraw() function with a provided version. This function collects the data currently held on file for a particular fund into a temporary array. It uses the data to calculate a suitable scale for the dates (x-axis) and the prices (y-axis). The data is presented as a line graph, which should enable the operator to spot any erratic data easily, with the exact values displayed at the graph points. Look through the code to see how the MFC drawing tool classes and the GDI drawing functions are used to display output in a device context.

  • To implement the OnDraw() method
    1. In ClassView, expand the CSTUploadView class icon.
    2. Double click the OnDraw() icon to edit the method.
    3. Replace the entire method with the following code:
    4. (This code can be found in CH5_07.cpp, installed from the companion CD.)

       void CSTUploadView::OnDraw(CDC* pDC) {      CSTUploadDoc* pDoc = GetDocument();      ASSERT_VALID(pDoc);      // Save the current state of the device context      int nDC = pDC->SaveDC();      const CStockDataList & pData = pDoc->GetDocList();      // Make a small array containing the      // records for the current fund.      // We use an array to take advantage of indexed access.      CArray<CStockData, CStockData &> arrFundData;      POSITION pos = pData.GetHeadPosition();      while(pos)      {           CStockData sd = pData.GetNext(pos);           if(sd.GetFund() == pDoc->GetCurrentFund())                arrFundData.Add(sd);      }      int nPrices = arrFundData.GetSize();      if(nPrices == 0)            return;      // Some constant sizes (in device units)      const int AXIS_DIVIDER_LENGTH = 6;      const int AXIS_FONT_HEIGHT = 24;      const int HEADING_FONT_HEIGHT = 36;      // Create font for axis labels      CFont AxisFont;      if(AxisFont.CreateFont(AXIS_FONT_HEIGHT, 0, 0, 0, 0, 0, 0, 0, 0,            0, 0, 0, FF_ROMAN, 0))           pDC->SelectObject(&AxisFont);      else      {           AfxMessageBox("Unable to create Axis font");           return;      }      CPen AxisPen;      if(AxisPen.CreatePen(PS_SOLID, 1, RGB(0,0,0)))           pDC->SelectObject(&AxisPen);      else      {           AfxMessageBox("Unable to create Axis Pen");           return;      }      // Array to graph coordinates as we go      CArray<CPoint, CPoint&> CoordArray;      for(int i = 0; i < nPrices; i++)           CoordArray.Add(CPoint(0, 0));      // Set viewport origin to bottom left corner of window      CPoint ptBottomLeft(0, -850);      pDC->LPtoDP(&ptBottomLeft);      pDC->SetViewportOrg(ptBottomLeft);      // Base coordinates for axes      const CPoint ORIGIN(100, 100);      const CPoint Y_EXTENT(ORIGIN.x, ORIGIN.y + 650);      const CPoint X_EXTENT(ORIGIN.x + 900, ORIGIN.y);      // Draw axes      pDC->MoveTo(Y_EXTENT);      pDC->LineTo(ORIGIN);      pDC->LineTo(X_EXTENT);      int nLabelPos = Y_EXTENT.y + ((ORIGIN.y - Y_EXTENT.y) / 2);      pDC->TextOut(ORIGIN.x - 50, nLabelPos, '$');      // Divide x-axis into number of prices held in the file      int nXIncrement = (X_EXTENT.x - ORIGIN.x) / nPrices;      double nMaxPrice = 0;      double nMinPrice = 0;      for(i = 0; i < nPrices; i++)      {           int xPoint = (ORIGIN.x + (i * nXIncrement));           CoordArray[i].x = xPoint;           pDC->MoveTo(xPoint, ORIGIN.y);           pDC->LineTo(xPoint, ORIGIN.y + AXIS_DIVIDER_LENGTH);           COleDateTime aDate = arrFundData[i].GetDate();           double aPrice = arrFundData[i].GetPrice();           nMaxPrice = max(nMaxPrice, aPrice);           nMinPrice = nMinPrice == 0 ?                 nMaxPrice :                min(nMinPrice, aPrice);           CString strDate = aDate.Format("%m/%d/%y");           if(i == 0 || i == (nPrices-1))                pDC->TextOut(xPoint-2,                      ORIGIN.y - AXIS_FONT_HEIGHT / 2, strDate);           else           {                CString strDay = strDate.Mid(                     strDate.Find('/') + 1);                strDay = strDay.Left(strDay.Find('/'));                pDC->TextOut(xPoint-6,                      ORIGIN.y - AXIS_FONT_HEIGHT / 2, strDay);           }      }      // Divide y-axis into suitable scale based on       // the difference between max and min prices on file      nMaxPrice += 2.0;      nMinPrice -= 1.0;      int iScale = int(nMaxPrice) - int(nMinPrice);      int nYIncrement = (ORIGIN.y - Y_EXTENT.y) / iScale;      for(i = 0; i < iScale; i++)      {           int yPoint = (ORIGIN.y - (i * nYIncrement));           pDC->MoveTo(ORIGIN.x, yPoint);           pDC->LineTo(ORIGIN.x - AXIS_DIVIDER_LENGTH, yPoint);           int iCurrentPrice = int(nMinPrice) + i;           for(int j = 0; j < nPrices; j++)           {                double aPrice = arrFundData[j].GetPrice();                if(aPrice >= double(iCurrentPrice) &&                      aPrice < double(iCurrentPrice) + 1.0)                {                     double dFraction = aPrice -                           double(iCurrentPrice);                     CoordArray[j].y =                          yPoint - int(dFraction *                                double(nYIncrement));                }           }           CString strPrice;           strPrice.Format("%d", iCurrentPrice);           int nTextSize = pDC->GetTextExtent(strPrice).cx;           nTextSize += 10;           pDC->TextOut(ORIGIN.x - nTextSize, yPoint+12, strPrice);      }      // Graph figures stored in CoordArray      CPen GraphPen;      if(GraphPen.CreatePen(PS_SOLID, 1, RGB(255,0,0)))  // Red pen        {           pDC->SelectObject(&GraphPen);      }      else      {           AfxMessageBox("Unable to create Graph Pen");           return;      }      // Draw Graph      // Label graph points with price value (in blue)      COLORREF crOldText = pDC->SetTextColor(RGB(0,0,255));      pDC->MoveTo(CoordArray[0]);      for(i = 0; i <nPrices; i++)      {           pDC->LineTo(CoordArray[i]);           CPoint TextPoint;           if((i+1) <nPrices)           {                if(CoordArray[i + 1].y >= CoordArray[i].y)                     TextPoint = CoordArray[i] + CPoint(5, 0);                else                     TextPoint = CoordArray[i] + CPoint(5,                           AXIS_FONT_HEIGHT);           }           else                TextPoint = CoordArray[i] + CPoint(5, 0);           CString strPrice;           strPrice.Format("%.2f", arrFundData[i].GetPrice());           pDC->TextOut(TextPoint.x, TextPoint.y, strPrice);      }      pDC->SetTextColor(crOldText);      // Create heading      CFont HeadingFont;      if(HeadingFont.           CreateFont(HEADING_FONT_HEIGHT, 0, 0, 0, FW_BOLD, 1, 0, 0,            0, 0, 0, 0, FF_ROMAN, 0));           pDC->SelectObject(&HeadingFont);      else      {           AfxMessageBox("Unable to create Heading Font");           return;      }      CString strHeading = pDoc->GetCurrentFund();      strHeading += " - Closing Prices ";      COleDateTime aDate = arrFundData[0].GetDate();      strHeading += aDate.Format("%m/%d/%y");       strHeading += " to ";      aDate = arrFundData[nPrices - 1].GetDate();      strHeading += aDate.Format("%m/%d/%y");      CSize sizeText = pDC->GetTextExtent(strHeading);      pDC->TextOut(X_EXTENT.x - sizeText.cx,            Y_EXTENT.y + sizeText.cy, strHeading);      // Restore the original device context      pDC->RestoreDC(nDC); } 

    5. Build and run the STUpload application. Test loading the data as before. The application data should now appear as shown in Figure 5.21.
    6. click to view at full size.

      Figure 5.21 The STUpload application



    Microsoft Press - Desktop Applications with Microsoft Visual C++ 6. 0. MCSD Training Kit
    Desktop Applications with Microsoft Visual C++ 6.0 MCSD Training Kit
    ISBN: 0735607958
    EAN: 2147483647
    Year: 1999
    Pages: 95

    flylib.com © 2008-2017.
    If you may any questions please contact us: flylib@qtcs.net