Windows Systems Programming: Spring 2002

[ Home | Syllabus | Course Notes | Assignments | Search]


Document View Example

SdiSquares Example Chapter 9. 4 x 4 grid of squares, can change color of each square using menu to select color and mouse to select square. Can save/restore from file.

Source Code is here .

Document/View divides responsibility among the underlying objects.

Start with the Document. What information about the application must be remembered?


In SquaresDoc.h

COLORREF m_clrCurrentColor; // current selected color
COLORREF m_clrGrid[4][4]; // color for each square
public:
   void SetSquare (int i, int j, COLORREF color);
   COLORREF GetSquare (int i, int j);
   COLORREF GetCurrentColor();
In SquaresDoc.cpp

BOOL CSquaresDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;

for (int i=0; i<4; i++)
for (int j=0; j<4; j++)
m_clrGrid[i][j] = RGB (255, 255, 255); // initially "white"

m_clrCurrentColor = RGB (255, 0, 0); // initially "red"
return TRUE;
}


Now look at how view uses this information to draw the screen

void CSquaresView::OnDraw(CDC* pDC) 
{
CSquaresDoc* pDoc = GetDocument(); 

ASSERT_VALID(pDoc);

//
// Set the mapping mode to MM_LOENGLISH.
//
pDC->SetMapMode (MM_LOENGLISH);


//
// Draw the 16 squares.
//
for (int i=0; i<4; i++) {
for (int j=0; j<4; j++) {
COLORREF color = pDoc->GetSquare (i, j);

CBrush brush (color);
int x1 = (j * 100) + 50; // do some arithmetic to define 1 inch squares
int y1 = (i * -100) - 50;
int x2 = x1 + 100;
int y2 = y1 - 100;
CRect rect (x1, y1, x2, y2);
pDC->FillRect (rect, &brush); // fill rectangle with colored brush
}
}

//
// Then the draw the grid lines surrounding them.
//
for (int x=50; x<=450; x+=100) {
pDC->MoveTo (x, -50);
pDC->LineTo (x, -450);
}

for (int y=-50; y>=-450; y-=100) {
pDC->MoveTo (50, y);
pDC->LineTo (450, y);
}
}

Important point is that view asked document for information needed to draw a view of the document.

NOTE: there are other ways to "view" this data - for example, a list of the colors of each square (white,red, red, green, ....) or put the color names in a grid. The document's data is the color of each of the 16 squares and the current selected color.


Changing Color (LButtonDown)

void CSquaresView::OnLButtonDown(UINT nFlags, CPoint point) 
{
CView::OnLButtonDown(nFlags, point);

//
// Convert to click coordinates to MM_LOENGLISH units.
//
CClientDC dc (this);
dc.SetMapMode (MM_LOENGLISH); 
CPoint pos = point;
dc.DPtoLP (&pos); // convert from device to logical point

//
// If a square was clicked, set its color to the current color.
//
if (pos.x >= 50 && pos.x <= 450 && pos.y <= -50 && pos.y >= -450) {
int i = (-pos.y - 50) / 100; // compute row and column
int j = (pos.x - 50) / 100;
CSquaresDoc* pDoc = GetDocument ();
COLORREF clrCurrentColor = pDoc->GetCurrentColor ();
pDoc->SetSquare (i, j, clrCurrentColor);

}
}



  Updating the view after document change

void CSquaresDoc::SetSquare(int i, int j, COLORREF color)
{
ASSERT (i >= 0 && i <= 3 && j >= 0 && j <= 3); // robust programming
m_clrGrid[i][j] = color; // update state of document object
SetModifiedFlag (TRUE); // so we are reminded before quitting
UpdateAllViews (NULL); // send message to view to update
}

Why call UpdateAllViews - why not let view do update directly since it calls SetSquare? because this allows the document to control when expensive updates need to be done.


Document handles all menu/menu update command messages (see routing). For example

void CSquaresDoc::OnUpdateColorRed(CCmdUI* pCmdUI) 
{
    pCmdUI->SetRadio (m_clrCurrentColor == RGB (255, 0, 0)); 
}


Serializing the Document

Document/View has a lot of support for saving/restoring documents to file. Has file new/open/save/save as menu items - supplies file selection dialog boxes. The only thing the document class must do is code which data members to save and how - and most MFC objects know how to save/restore themselves using overloads to the "<<" and ">>" operators. Here is the code here

void CSquaresDoc::Serialize(CArchive& ar) // CArchive is a file
{
if (ar.IsStoring()) // ask if saving or restoring
{ // save data
for (int i=0; i<4; i++)
for (int j=0; j<4; j++)
ar << m_clrGrid[i][j];  // COLOREF object knows how to save itself
ar << m_clrCurrentColor;
}
else
{ // restore data
for (int i=0; i<4; i++)
for (int j=0; j<4; j++)
ar >> m_clrGrid[i][j];
ar >> m_clrCurrentColor;
}
}

 


Copyright chris wild 1999-2002.
For problems or questions regarding this web contact [Dr. Wild].
Last updated: February 10, 2002.