Windows NT Systems Programming

[ Home | Syllabus |Course Notes]


Paint 4


Responsibilities of the Application


Source Code Paint4.cpp

CPaintApp myApp;

BEGIN_MESSAGE_MAP (CPaintApp, CWinApp)
    ON_COMMAND (ID_FILE_NEW, CWinApp::OnFileNew)
    ON_COMMAND (ID_FILE_OPEN, CWinApp::OnFileOpen)
    ON_COMMAND (ID_APP_ABOUT, OnAppAbout)
END_MESSAGE_MAP ()

BOOL CPaintApp::InitInstance ()
{
    SetRegistryKey ("Programming Windows 95 with MFC");
    LoadStdProfileSettings ();

    CSingleDocTemplate* pDocTemplate;
    pDocTemplate = new CSingleDocTemplate (
        IDR_MAINFRAME,
        RUNTIME_CLASS (CPaintDoc),
        RUNTIME_CLASS (CMainFrame),
        RUNTIME_CLASS (CPaintView)
    );

    AddDocTemplate (pDocTemplate);
    RegisterShellFileTypes (TRUE);

    CCommandLineInfo cmdInfo;
    ParseCommandLine (cmdInfo);

    if (!ProcessShellCommand (cmdInfo))
        return FALSE;

    m_pMainWnd->DragAcceptFiles ();
    return TRUE;
}

void CPaintApp::OnAppAbout ()
{
    CAboutDialog dlg;
    dlg.DoModal ();
}

rainbow.gif (2243 bytes)


Responsibilities of the Document


Paint4Doc.h

class CPaintDoc : public CDocument
{
    DECLARE_DYNCREATE (CPaintDoc)

private:
    UINT m_nWidth;
    UINT m_nColor;
    CObArray m_lineArray;

    void InitWidthAndColor (); // initializes on Open/New

public:
    static const COLORREF m_crColors[8]; // can choose between 8 colors

    CPaintDoc ();
    virtual BOOL OnNewDocument ();
    virtual BOOL OnOpenDocument (LPCTSTR);
    virtual void DeleteContents ();
    virtual void Serialize (CArchive&);

    CLine* AddLine (CPoint, CPoint);
    CLine* GetLine (int);
    int GetLineCount ();

protected:
    afx_msg void OnWidth (UINT);
    afx_msg void OnColor (UINT);
    afx_msg void OnUpdateWidthUI (CCmdUI*);
    afx_msg void OnUpdateColorUI (CCmdUI*);

    DECLARE_MESSAGE_MAP ()
};

rainbow.gif (2243 bytes)


Paint4Doc.cpp

BEGIN_MESSAGE_MAP (CPaintDoc, CDocument)
    ON_COMMAND_RANGE (ID_WIDTH_VTHIN, ID_WIDTH_VTHICK, OnWidth)
    ON_COMMAND_RANGE (ID_COLOR_BLACK, ID_COLOR_WHITE, OnColor)
    ON_UPDATE_COMMAND_UI_RANGE (ID_WIDTH_VTHIN, ID_WIDTH_VTHICK,
        OnUpdateWidthUI)
    ON_UPDATE_COMMAND_UI_RANGE (ID_COLOR_BLACK, ID_COLOR_WHITE,
        OnUpdateColorUI)
END_MESSAGE_MAP ()

const COLORREF CPaintDoc::m_crColors[8] = {
    RGB (  0,   0,   0),    // Black
    RGB (  0,   0, 255),    // Blue
    RGB (  0, 255,   0),    // Green
    RGB (  0, 255, 255),    // Cyan
    RGB (255,   0,   0),    // Red
    RGB (255,   0, 255),    // Magenta
    RGB (255, 255,   0),    // Yellow
    RGB (255, 255, 255)     // White
};

CPaintDoc::CPaintDoc ()
{
    m_lineArray.SetSize (0, 64);
}

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

    InitWidthAndColor (); // needed because SDI (constructor won't work)
    return TRUE;
}

BOOL CPaintDoc::OnOpenDocument (LPCTSTR lpszPathName)
{
    if (!CDocument::OnOpenDocument (lpszPathName)) // work done here (dialog box)
        return FALSE;

    InitWidthAndColor ();
    return TRUE;
}

void CPaintDoc::InitWidthAndColor ()
{
    m_nColor = ID_COLOR_RED - ID_COLOR_BLACK;
    m_nWidth = ID_WIDTH_MEDIUM - ID_WIDTH_VTHIN;
}

void CPaintDoc::DeleteContents ()
{
    int nCount = m_lineArray.GetSize ();

    if (nCount) {
        for (int i=0; i<nCount; i++)
            delete m_lineArray[i]; // Array of Pointers - delete heap memory
        m_lineArray.RemoveAll ();
    }
}

void CPaintDoc::Serialize (CArchive& ar)
{
    m_lineArray.Serialize (ar);
}

CLine* CPaintDoc::AddLine (CPoint ptFrom, CPoint ptTo)
{
    static UINT nWidths[5] = { 1, 8, 16, 24, 32 };

    CLine* pLine;
    try {
        pLine = new CLine (ptFrom, ptTo, nWidths[m_nWidth],
            m_crColors[m_nColor]);
        m_lineArray.Add (pLine);
        SetModifiedFlag ();
    }
    catch (CMemoryException* e) {
        if (pLine != NULL) {
            delete pLine;
            pLine = NULL;
        }
        AfxMessageBox ("Out of memory", MB_ICONSTOP | MB_OK);
        e->Delete ();
    }
    return pLine;
}

CLine* CPaintDoc::GetLine (int nIndex)
{
    return (CLine*) m_lineArray[nIndex];
}

int CPaintDoc::GetLineCount ()
{
    return m_lineArray.GetSize ();
}

void CPaintDoc::OnWidth (UINT nID)
{
    m_nWidth = nID - ID_WIDTH_VTHIN;
}

void CPaintDoc::OnColor (UINT nID)
{
    m_nColor = nID - ID_COLOR_BLACK;
}

void CPaintDoc::OnUpdateWidthUI (CCmdUI* pCmdUI)
{
    pCmdUI->SetCheck ((pCmdUI->m_nID - ID_WIDTH_VTHIN) == m_nWidth);
}

void CPaintDoc::OnUpdateColorUI (CCmdUI* pCmdUI)
{
    pCmdUI->SetCheck ((pCmdUI->m_nID - ID_COLOR_BLACK) == m_nColor);
}

rainbow.gif (2243 bytes)


Responsibility of the View


PAINT4VIEW.H

class CPaintView : public CScrollView
{
    DECLARE_DYNCREATE (CPaintView)

private:
    CPoint m_ptFrom;
    CPoint m_ptTo;

    CPaintDoc* GetDocument () { return (CPaintDoc*) m_pDocument; }
    void InvertLine (CDC*, CPoint, CPoint);

public:
    virtual void OnInitialUpdate (); // OVERRIDE

protected:
    virtual void OnDraw (CDC*);

    afx_msg void OnLButtonDown (UINT, CPoint);
    afx_msg void OnMouseMove (UINT, CPoint);
    afx_msg void OnLButtonUp (UINT, CPoint);
    afx_msg void OnContextMenu (CWnd*, CPoint);

    DECLARE_MESSAGE_MAP ()
};

rainbow.gif (2243 bytes)


PAINT4VIEW.CPP


void CPaintView::OnInitialUpdate ()
{
    SetScrollSizes (MM_TEXT, CSize (2048, 2048));
    CScrollView::OnInitialUpdate ();
}

void CPaintView::OnDraw (CDC* pDC)
{
    CPaintDoc* pDoc = GetDocument ();
    int nCount = pDoc->GetLineCount ();

    if (nCount) {
        for (int i=0; i<nCount; i++)
            pDoc->GetLine (i)->Draw (pDC);
    }
}

void CPaintView::OnLButtonDown (UINT nFlags, CPoint point)
{
    CClientDC dc (this);
    OnPrepareDC (&dc);
    dc.DPtoLP (&point);

    m_ptFrom = point;
    m_ptTo = point;
    SetCapture ();
}

void CPaintView::OnMouseMove (UINT nFlags, CPoint point)
{
    if (GetCapture () == this) {
        CClientDC dc (this);
        OnPrepareDC (&dc);
        dc.DPtoLP (&point);

        InvertLine (&dc, m_ptFrom, m_ptTo); // "Erases" temporary rubber band line
        InvertLine (&dc, m_ptFrom, point); // And Draws a new one
        m_ptTo = point;
    }
}

void CPaintView::OnLButtonUp (UINT nFlags, CPoint point)
{
    if (GetCapture () == this) {
        ReleaseCapture ();
        CClientDC dc (this);
        OnPrepareDC (&dc);
        dc.DPtoLP (&point);
        InvertLine (&dc, m_ptFrom, m_ptTo); // erase temporary line

        CLine* pLine = GetDocument ()->AddLine (m_ptFrom, point); // Add a permanent line to the document
        if (pLine != NULL)
            pLine->Draw (&dc); // And Draw it (more efficient than calling OnDraw)
    }
}

void CPaintView::InvertLine (CDC* pDC, CPoint ptFrom, CPoint ptTo)
{
    int nOldMode = pDC->SetROP2 (R2_NOT);

    pDC->MoveTo (ptFrom);
    pDC->LineTo (ptTo);

    pDC->SetROP2 (nOldMode);
}

void CPaintView::OnContextMenu (CWnd* pWnd, CPoint point)
{
    CMenu menu;
    menu.LoadMenu (IDR_CONTEXTMENU);
    CMenu* pContextMenu = menu.GetSubMenu (0);

    for (int i=0; i<8; i++)
        pContextMenu->ModifyMenu (ID_COLOR_BLACK + i,
            MF_BYCOMMAND | MF_OWNERDRAW, ID_COLOR_BLACK + i);

    pContextMenu->TrackPopupMenu (TPM_LEFTALIGN | TPM_LEFTBUTTON |
        TPM_RIGHTBUTTON, point.x, point.y, AfxGetMainWnd ());
}

rainbow.gif (2243 bytes)


Cline.h

class CLine : public CObject
{
    DECLARE_SERIAL (CLine)

private:
    CPoint m_ptFrom;
    CPoint m_ptTo;
    UINT m_nWidth;
    COLORREF m_crColor;

public:
    CLine () {}
    CLine (CPoint, CPoint, UINT, COLORREF);
    virtual void Serialize (CArchive&);
    virtual void Draw (CDC*);
};

CLine.cpp

IMPLEMENT_SERIAL (CLine, CObject, 1) // 1 is version number

CLine::CLine (CPoint ptFrom, CPoint ptTo, UINT nWidth, COLORREF crColor)
{
    m_ptFrom = ptFrom;
    m_ptTo = ptTo;
    m_nWidth = nWidth;
    m_crColor = crColor;
}

void CLine::Serialize (CArchive& ar)
{
    CObject::Serialize (ar);

    if (ar.IsStoring ())
        ar << m_ptFrom << m_ptTo << m_nWidth << (DWORD) m_crColor;
    else
        ar >> m_ptFrom >> m_ptTo >> m_nWidth >> (DWORD) m_crColor;
}

void CLine::Draw (CDC* pDC)
{
    CPen pen (PS_SOLID, m_nWidth, m_crColor);

    CPen* pOldPen = pDC->SelectObject (&pen);
    pDC->MoveTo (m_ptFrom);
    pDC->LineTo (m_ptTo);

    pDC->SelectObject (pOldPen);
}

Copyright chris wild 1997.
For problems or questions regarding this web contact [Dr. Wild].
Last updated: October 20, 1997.