1. 接下来将展示Squres应用程序来说明单文档界面程序的编写:
1) 视图用来显示一个4×4的网格,初始化时每个网格都是白色的(即新建文档时);
2) 菜单栏中有一个Color子菜单,可以选择当前要填充的颜色,总共共有6中,而初始时默认将红色作为当前填充色;
3) 可以用鼠标点击网格中的格子,之后会用当前选中的填充色来填充选中的格子;
4) 程序文档的后缀是.sqr,里面就保存4×4网格中各个格子的颜色,以及当前选中的填充色;
2. 程序的创建:
1) 还是选择MFC[.exe]模板;
2) 第一步中选择Single document选项,并且要选中Document/View architecture support?复选框;
3) 而在第3步中的Advanced选项卡中填写默认的文件扩展名.sqr就行了(Wizzard会自动将该扩展名写入程序的字符串资源当中);
4) 由于程序简单,只需要修改Document类和View类即可;
3. CSquresDocument:
.h:
// SquresDoc.h : interface of the CSquresDoc class
//
/////////////////////////////////////////////////////////////////////////////
#if !defined(AFX_SQURESDOC_H__29091B77_23ED_4908_817F_F58907F39F60__INCLUDED_)
#define AFX_SQURESDOC_H__29091B77_23ED_4908_817F_F58907F39F60__INCLUDED_
#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000
class CSquresDoc : public CDocument
{
protected: // create from serialization only
CSquresDoc();
DECLARE_DYNCREATE(CSquresDoc)
// Attributes
public:
// Operations
public:
// Overrides
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CSquresDoc)
public:
virtual BOOL OnNewDocument();
virtual void Serialize(CArchive& ar);
//}}AFX_VIRTUAL
// Implementation
public:
COLORREF GetCurrentColor(); // 获取当前选中的颜色
void SetSquareColor(COLORREF color, int i, int j); // 修改某一网格的颜色
COLORREF GetSquareColor(int i, int j); // 获取某一网格的颜色
virtual ~CSquresDoc();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// Generated message map functions
protected:
static COLORREF clrChoiceOnly[6]; // 保存只能选择的6中颜色
COLORREF m_clrGrid[4][4]; // 4×4的网格,存放每个格子中的颜色
COLORREF m_clrCurrentColor; // 当前选中的颜色
//{{AFX_MSG(CSquresDoc)
// NOTE - the ClassWizard will add and remove member functions here.
// DO NOT EDIT what you see in these blocks of generated code !
//}}AFX_MSG
afx_msg void OnColor(UINT nID); // 选中Color菜单
afx_msg void OnUpdateColor(CCmdUI* pCmdUI); // 更新Color菜单项(单选按钮选中)
DECLARE_MESSAGE_MAP()
};
/////////////////////////////////////////////////////////////////////////////
//{{AFX_INSERT_LOCATION}}
// Microsoft Visual C++ will insert additional declarations immediately before the previous line.
#endif // !defined(AFX_SQURESDOC_H__29091B77_23ED_4908_817F_F58907F39F60__INCLUDED_)
.cpp:
// SquresDoc.cpp : implementation of the CSquresDoc class
//
#include "stdafx.h"
#include "Squres.h"
#include "SquresDoc.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
COLORREF CSquresDoc::clrChoiceOnly[6] = {
RGB(255, 0, 0), // 红
RGB(255, 255, 0), // 黄
RGB(0, 255, 0), // 绿
RGB(0, 255, 255), // 青黄
RGB(0, 0, 255), // 蓝
RGB(255, 255, 255) // 白
};
/////////////////////////////////////////////////////////////////////////////
// CSquresDoc
IMPLEMENT_DYNCREATE(CSquresDoc, CDocument)
BEGIN_MESSAGE_MAP(CSquresDoc, CDocument)
//{{AFX_MSG_MAP(CSquresDoc)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
ON_COMMAND_RANGE(ID_COLOR_RED, ID_COLOR_WHITE, OnColor)
ON_UPDATE_COMMAND_UI_RANGE(ID_COLOR_RED, ID_COLOR_WHITE, OnUpdateColor)
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSquresDoc construction/destruction
CSquresDoc::CSquresDoc()
{
// TODO: add one-time construction code here
}
CSquresDoc::~CSquresDoc()
{
}
BOOL CSquresDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: add reinitialization code here
// (SDI documents will reuse this document)
// 对于新建的文档,颜色都初始化为白色
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
m_clrGrid[i][j] = RGB(255, 255, 255);
m_clrCurrentColor = RGB(255, 0, 0); // 而当前颜色初始化为红色
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CSquresDoc serialization
// 串行化时先串行化网格最后再串行化当前颜色
void CSquresDoc::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{
// TODO: add storing code here
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
ar << m_clrGrid[i][j];
ar << m_clrCurrentColor;
}
else
{
// TODO: add loading code here
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++)
ar >> m_clrGrid[i][j];
ar >> m_clrCurrentColor;
}
}
/////////////////////////////////////////////////////////////////////////////
// CSquresDoc diagnostics
#ifdef _DEBUG
void CSquresDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CSquresDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CSquresDoc commands
COLORREF CSquresDoc::GetSquareColor(int i, int j)
{
ASSERT(0 <= i && i <= 3 && 0 <= j && j <= 3);
return m_clrGrid[i][j];
}
void CSquresDoc::SetSquareColor(COLORREF color, int i, int j)
{
ASSERT(0 <= i && i <= 3 && 0 <= j && j <= 3);
m_clrGrid[i][j] = color;
// 颜色修改后需要及时更新视图
SetModifiedFlag(TRUE);
UpdateAllViews(NULL);
}
COLORREF CSquresDoc::GetCurrentColor()
{
return m_clrCurrentColor;
}
void CSquresDoc::OnColor(UINT nID)
{
m_clrCurrentColor = clrChoiceOnly[nID - ID_COLOR_RED];
}
void CSquresDoc::OnUpdateColor(CCmdUI* pCmdUI)
{
pCmdUI->SetRadio(m_clrCurrentColor == clrChoiceOnly[pCmdUI->m_nID - ID_COLOR_RED]);
}
4. CSquresView:
.h:只需添加一个处理鼠标左击的处理程序即可
protected:
//{{AFX_MSG(CSquresView)
// 左键击中网格使之改变为当前选中的颜色
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
//}}AFX_MSG
.cpp:
// SquresView.cpp : implementation of the CSquresView class
//
#include "stdafx.h"
#include "Squres.h"
#include "SquresDoc.h"
#include "SquresView.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CSquresView
IMPLEMENT_DYNCREATE(CSquresView, CView)
BEGIN_MESSAGE_MAP(CSquresView, CView)
//{{AFX_MSG_MAP(CSquresView)
ON_WM_LBUTTONDOWN()
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CSquresView construction/destruction
CSquresView::CSquresView()
{
// TODO: add construction code here
}
CSquresView::~CSquresView()
{
}
BOOL CSquresView::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: Modify the Window class or styles here by modifying
// the CREATESTRUCT cs
return CView::PreCreateWindow(cs);
}
/////////////////////////////////////////////////////////////////////////////
// CSquresView drawing
void CSquresView::OnDraw(CDC* pDC)
{
CSquresDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
// TODO: add draw code for native data here
pDC->SetMapMode(MM_LOENGLISH);
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4; j++) {
COLORREF color = pDoc->GetSquareColor(i, j);
CBrush brush(color);
int x1 = j * 100 + 50;
int y1 = i * -100 - 50;
int x2 = x1 + 100;
int y2 = y1 - 100;
CRect rect(x1, y1, x2, y2);
pDC->FillRect(rect, &brush);
}
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);
}
}
/////////////////////////////////////////////////////////////////////////////
// CSquresView diagnostics
#ifdef _DEBUG
void CSquresView::AssertValid() const
{
CView::AssertValid();
}
void CSquresView::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CSquresDoc* CSquresView::GetDocument() // non-debug version is inline
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CSquresDoc)));
return (CSquresDoc*)m_pDocument;
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CSquresView message handlers
void CSquresView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: Add your message handler code here and/or call default
CView::OnLButtonDown(nFlags, point);
CClientDC dc(this);
dc.SetMapMode(MM_LOENGLISH);
CPoint pos = point;
dc.DPtoLP(&pos); // 调整成逻辑位置
// 先判断是否击中在网格内
if (50 <= pos.x && pos.x <= 450 && -450 <= pos.y && pos.y <= -50) {
int i = (-pos.y - 50) / 100;
int j = (pos.x - 50) / 100;
CSquresDoc* pDoc = GetDocument();
COLORREF clrCurrentColor = pDoc->GetCurrentColor();
pDoc->SetSquareColor(clrCurrentColor, i, j); // 设置新的网格颜色
}
}