Visual C++ Workshop
Session 9
R. Eckert

MFC WINDOWS PROGRAMMING--DOCUMENT/VIEW APPROACH

APP/WINDOW approach creates application and window objects
     Mirrors way Win32 API programs are organized
     Main difference--MFC automates and masks many details
     But data and rendering of data are intertwined
     And frequently, data members exist within window class
          Example in MSG1.CPP:
               Output string & position both defined in window-based class
                     Output string is data
                     Position is user defined

Conceptually data is different from rendering of data
In an APP/WINDOW they are mixed together in same window class

Frequently need to have different views of same data
     (e.g., displaying data in a window or on a printer)
So it would be good to separate data and data presentation

DOCUMENT/VIEW approach achieves this separation:
     Encapsulates data in a CDocument class object
     Encapsulates data display mechanism data in a CView class object

Classes derived from CDocument --
     Should handle anything affecting an application's data

Classes derived from CView--
     Should handle display of data and user interactions with that display

Still need to create CFrameWnd and CWinApp classes
     But their roles are reduced

Document--Any forms of data associated with the application (pure data)
     Not limited to text
     Could be anything: game data, graphical data, etc. 

Document Interfaces--

Single Document interface (SDI) application--
     Program that deals with one document at a time 
          All programs to date have been SDI programs

Multiple Document Interface (MDI) application--
     Program organized to handle multiple documents simultaneously
          Multiple open documents can be of same or different types
     Example of an MDI application: Microsoft Word

View--A rendering of a document; a physical representation of the data
    Provides mechanism for displaying data stored in a document
    Defines how data is to be displayed in a window
    Defines how the user can interact with it

Frame Window--window in which a view of a document is displayed

A document can have multiple views associated with it
     (different ways of looking at the same data)

But a view has only one document associated with it


MFC Template class object--
     Handles coordination between documents, views, and frame windows

In general:
     Application object creates a template:
          which coordinates the display of a document's data…
                in a view…
                     inside a frame window (See following diagram.)

Serialization--
     Provides for storage/retrieval of document data
          Usually to/from a disk file
CDocument class has serialization built into it
     In DOCUMENT/VIEW apps, saving/storing data is straightforward

Dynamic Creation--
     In DOCUMENT/VIEW approach, objects are dynamic
     DOCUMENT/VIEW program is run
          Its frame window, document, and view are created dynamically
               DOC/VIEW objects synthesized from file data
               Need to be created at load time 
               To allow for dynamic creation, following macros used 
               (in classes derived from CFrameWnd, CDocument, and CView):

     DECLARE_DYNCREATE(class_name)  // in declaration (.h file)

     IMPLEMENT_DYNCREATE(class_name, parent_class_name)  // (in .cpp file)

IMPLEMENT_DYNCREATE() macro is invoked
     Class is enabled for dynamic creation
     Now a template can be created

Document/View Programs--

Almost always have at least four classes derived from:
     CFrameWnd
     CDocument
     CView
     CWinApp
Usually put into separate declaration and implementation files
Because of template and dynamic creation, there is lots of initialization
Could be done by hand, but nobody does it that way

Instead use Microsoft Developer Studio AppWizard and ClassWizard  tools:

AppWizard--

Tool that generates a DOC/VIEW MFC program framework  automatically
     Can be built on and customized by programmer
     Provides fast, efficient way of producing Microsoft Windows programs     
     Performs required initialization automatically     
     Creates functional CFrameWnd, CView, CDocument, CWinApp classes   
     After AppWizard does it's thing:
          Application can be built and run
              Full-fledged window with all common menu items, tools, etc
              (window doesn't do anything)

Message Handling in a Framework-based MFC App using ClassWizard--

ClassWizard--

Tool that connects resources & user-generated events to pgm response code 
Can write C++ skeleton routines to handle messages
     Inserts code into appropriate places in program
     Code then can then be customized by hand
Can used to help derive classes from MFC base classes

SKETCH Application: Example of Using AppWizard and ClassWizard--



User can use mouse as a drawing pencil
Left mouse button down
     line in window follows mouse motion
Left mouse button up
     Sketching stops
User clicks  "Drawing Color" menu item
     Popup menu with selections: "Red", "Green", "Blue"
          Used to choose drawing color
User clicks "Clear" menu item
     window client area is erased

Sketch data (points) won't be saved
     Leave CDocument class created by AppWizard alone:
          Called CSketchDoc class in sketchDoc.h and sketchDoc.cpp
Base functionality of CWinApp and CFrameWnd classes are adequate
     Leave them alone:
          Called CSketchApp class in sketch.h and sketch.cpp
          And CMainFrame class in MainFrm.h and MainFrm.cpp

Use ClassWizard to add sketching & color functionality to CView class:    
     Called CSketchView in sketchView.h and sketchView.cpp


Steps in Setting up AppWizard to Generate SKETCH Framework--

1.   From VC++ Visual Studio: "File | New | Projects-tab"
     Choose "MFC AppWizard (exe)"
     Enter name of the project (here "sketch")

2.   In resulting "MFC AppWizard-Step 1" window, 
     Choose "Single document" radio button
     Press "Next" button

3.   In next two windows ("Step 2 of 6" and "Step 3 of 6"), 
     Press "Next" button

4.   In resulting "Step 4 of 6" window, 
     Uncheck: "Docking toolbar", "Initial status bar", "Printing and print preview"
        Only "3D controls" check box remains checked
     Press "Finish" and "OK" buttons
     AppWizard creates all source files in the MFC, SDI, DOC/VIEW app
     "Build" project (as always) and run application
        Full-fledged window with lots of functionality

Now use ClassWizard to make it into what we want: the sketching app

Sketching Requirements--

If left mouse button is down:
     Each time mouse moves:
          Get current point (from  mouse move message data)
          Get a device context and pen of drawing color
          Select pen into DC
          Move to old point
          Draw line from old point to current point
          Make current point become old point
          Select pen out of device context

Use following variables--

BOOLEAN m_butdn flag: left button state
CPoint structures (m_ptold and m_pt): old and current points
CDC object pointer (*pDC): to access DC drawing functions
COLORREF variable (nColor): current drawing color
     (Selected by user from "Drawing color" popup menu)

Declaring Variables in the sketchView.h File--

Choose ClassView Icon in project workspace window (left side)
Expand it, and double click on CSketchView
     sketchView.h file comes into editing window (right side)

After the lines:

class CSketchView : public CView
{

Enter following code to declare the variables:
(Could also be done by right clicking on CSketchView and choosing
 "Add Member Variable"--just fill in the resulting dialog box)

protected:
    CPoint             m_ptold, m_pt;
    BOOL               m_butdn;
    CDC                *pDC;
    COLORREF           nColor;

Changing the Menu--

Choose ResourceView icon in project workspace window
Expand "sketch resources" folder and Menu subfolder
Double click IDR_MAINFRAME
     Menu editor appears
     App already has "File", "Edit" popup menus with several standard items  
     Since App will not do any file I/O or editing
        Use  <Delete> keyboard key to delete all "File" entries except "Exit"    
        Delete entire "Edit" popup menu
Add a popup menu called "Drawing Color" with items:
     "Red" (IDM_RED), "Green" (IDM_GREEN), and "Blue" (IDM_BLUE) 
Add another menu item called "Clear" (IDM_CLEAR) to main menu bar
Drag "Help" menu item to right side of the menu bar

Removing the Accelerator Table--

Close menu editor
Expand "sketch resources" Accelerator subfolder in ResourceView
Delete IDR_MAINFRAME accelerator by selecting it and using  <Delete>


Adding Code to the sketchView.cpp File--

Use ClassWizard to add code to respond to following messages:
     WM_LBUTTONDOWN, WM_LBUTTONUP, WM_MOUSEMOVE,          
     WM_COMMAND menu messages

Code Requirements--

WM_LBUTTONDOWN
     Set m_butdn to TRUE and record point in m_ptold
WM_LBUTTONUP
     Set m_butdn to FALSE
"Drawing Color" menu choices
     Set nColor to the appropriate COLORREF with RGB()
"Clear" menu choice
     Invalidate window's client area to force a WM_PAINT message
WM_MOUSEMOVE
     If mouse button is down (m_butdn==TRUE):
          Get pointer to a device context, pDC, with GetDC()
          Set m_pt to point data from mouse message
          Construct solid pen of color nColor using CPen class constructor
          Use pDC's member functions:
               SelectObject() to select pen into the device context    
               MoveTo(m_ptold) to move it to old point
               LineTo(m_pt) to draw line to new point
          Set m_ptold equal to m_pt
          Use pDC's SelectObject() to select the pen out of the DC
          (Automatically class destructor will destroy pen and DC)


Using ClassWizard to Implement Requirements--

Starting ClassWizard--
Easiest way: Click ClassWizard Toolbar Button:  
     (May or may not be visible on Developer Studio main menu bar)
     If not displayed, to add it:
          Right-click menu bar
          Select "Customize..." from resulting popup
          Under "Category:" combo box, select "View"
               ClassWizard Toolbar Button appears in "Buttons" area
               Drag it to the menu bar

Other ways of starting ClassWizard:
      Press <Ctrl>-w or 
      Select "View | ClassWizard" from Developer Studio's menu bar

Result of starting ClassWizard: "MFC ClassWizard" Dialog Box

"MFC ClassWizard" Dialog Box--

Should have "sketch" in "Project:" box, "CSketchView" in "Class name:" box 
Scroll through "Messages" list to find messages we want to respond to:     
     Scroll and select WM_LBUTTONDOWN
     Press "Add Function" button
          Class Wizard adds skeleton code in right places to:
               Set up CSketchView's message map
               Will contain OnLButtonDown() handler
     Click the "Edit Code" button
          Taken to exact place in code where additions must be made
          Has a comment: 
               //TODO: Add your message handler code here
     Add following after "//TODO" line:
          m_butdn = TRUE;
          m_ptold = point;

Go back to ClassWizard (<ctrl>-w)
Use it in same way to add WM_LBUTTONUP handler
     Add following line of code after resulting "//TODO":
          m_butdn = FALSE;

Use ClassWizard to add WM_MOUSEMOVE handler and following code:
          if (m_butdn)
          {
              pDC = GetDC();
              m_pt = point;
              CPen pPen(PS_SOLID, 1, nColor);
              CPen *pPenOld = pDC->SelectObject(&pPen);
              pDCMoveTo(m_ptold);
              pDCLineTo(m_pt);
              m_ptold = m_pt;
              pDC->SelectObject(pPenOld);
          }

Adding the WM_COMMAND menu item handlers--

Invoke ClassWizard and scroll "ObjectIDs" list (not "Messages")
     Scroll to "IDM_BLUE" inserted by Dev Studio's integrated environment 
     Select it and choose "COMMAND" in "Messages" list box
     Click "Add Function" button 
     Click "OK" in resulting "Add Member Function" dialog box
          ClassWizard generates On_Blue() handler to message map
     Press "Edit Code" to go to skeleton handler and add following code:
          nColor = RGB(0,0,255);

Use same procedure is to add  OnGreen() and OnRed() handlers

Add OnClear() handler in same way, code to be added:
          Invalidate(TRUE);

Member Variable Initialization--

All data members added to CSketchView class need to be initialized
     If not, they will contain garbage when application begins
Place initialization code CSketchView constructor:
     Go back to project workspace window 
     From Project Workspace window choose ClassView icon
     Expand "sketch classes" icon and CSketchView Class icon
     Double click on CSketchView() constructor
     Add following initialization code under "//TODO" comment:
          m_pt = m_ptold = CPoint(0,0);
          m_butdn = FALSE;
          nColor = RGB(0,0,0);  // initial drawing color black

Build project as usual
If no errors
     Functioning DOCUMENT/VIEW color sketching application


Using Modal Dialog Boxes in MFC Wizard-Generated Frameworks--
 
Must do the following:
     Insert dialog box template into the program's resources (as usual)
     Instantiate a CDialog-based object
     Call object's DoModal() function

Exchanging data between dialog box control and CDialog member variables--

Method 1:
     Get a pointer to control's ID with CWnd::GetDlgItem()
     Use pointer to send appropriate messages to control
           (as in DIALG2 example)
     OK for non-Wizard-generated apps
     Not convenient for Wizard-generated apps

Method 2:
     Use DDX (Dynamic Data Exchange) mechanism:
          DDX system moves data between dialog box controls and variables    
          Occurs when call is made to CWnd member function UpdateData(dir)     
               Boolean parameter dirdirection of data movement:
                    TRUE==>from controls to variables
                    FALSE==>from variables to controls
     MFC library's DoModal() function calls UpdateData(FALSE) 
          (Called by your application to start the dialog box)
             ==>Data from pgm variables transferred to dialog box's controls
     MFC library's OnOK() member function calls UpdateData(TRUE)
          (Called when user clicks "OK" button inside dialog box)
             ==>Data from dialog box's controls transferred to pgm variables
      OnOK() then calls CDialog::EndDialog()
          Dialog box disappears and DoModal() returns
          Destructor destroys the dialog box
     
This sequence often used in simple apps that don't call UpdateData() explicitly

SKETCH3 Applicdation: Adding a Text-Display Modal Dialog Box to SKETCH--



Has new "Text" menu item (ID = IDM_TEXT)
User clicks "Text"
     Modal dialog box appears
     Allows user to enter:
          Line of text to be displayed in sketching window
          (x,y) coordinates where text is to be displayed

Dialog box (IDD_TEXT) contents:
     Three static controls
          (labeled "x", "y", and "Text String")
     Three single-line edit controls
           (IDC_X, IDC_Y, IDC_TEXTEDIT)
     Standard "OK" and "Cancel" buttons



Steps in Modifying SKETCH Application Code--

1.   ResourceView's menu editor:
     Add new "Text" (ID=IDM_TEXT) menu item to SKETCH menu bar

2.   ResourceView's dialog box editor:
     "Insert | Resource | Dialog | New" to set up new dialog box:
          (IDD_TEXT, "Enter Text")
     Position each dialog box control
     Right click"Properties" box to enter ID and/or caption
          [Don't double click
               Dev Studio would ask to create new dialog class--NOT NOW!
               Wait until finished setting up dialog box] 
3.   ClassWizard to create the new class (<Ctrl>-w)
     Respond to class name prompt with CTextDlg
     Accept default base class (CDialog)

4.   Select "Member Variables" tab
          Make sure that "Class name:" is CtextDlg
          (ClassWizard has placed control IDs in a table) 
     Select each control
     Choose "Add Variable"
     Fill in resulting "Add Member Variable" dialog box as follows:

     ControlIDs       Type      Member
     ---------------------------------
     IDC_TEXTEDIT     CString   m_text
     IDC_X            UINT      m_x
     IDC_Y            UINT      m_y


5.   ClassWizard to add OnText() handler
          Will respond to the new IDM_TEXT menu item
     Enter handler code:

        CTextDlg dlg;
        dlg.DoModal();
        pDC = GetDC();
        pDCSetTextColor(nColor);
        pDCTextOut(dlg.m_x,dlg.m_y,dlg.m_text,lstrlen(dlg.m_text));

6. At top of sketchView.cpp file, with other include statements, type in:

 #include "TextDlg.h"

7. Build and run new version of SKETCH