使用MFC框架文档操作范例:
创建工程
创建工程,其中:
1、MFC单文档
2、自定义改应用程序数据文件扩展名:
3、 最后一步选择CListView(用报表显示数据)
重点问题:数据文件的读写功能
添加数据类
学生类,如下:
#pragma once
class CStudent
{
public:
CStudent(void);
~CStudent(void);
virtual void Serialize(CArchive& ar);
CString name;
CString department;
CString major;
CString grade;
CString classname;
CString cid;
};
#include "stdafx.h"
#include "Student.h"
CStudent::CStudent(void)
{
}
CStudent::~CStudent(void)
{
}
void CStudent::Serialize(CArchive& ar)
{
if (ar.IsStoring())
{ // storing code
ar<<name<<department<<major<<grade<<classname<<cid;
}
else
{ // loading code
ar>>name>>department>>major>>grade>>classname>>cid;
}
}
文档类:
// MFC05Doc.h : CMFC05Doc 类的接口
//
#pragma once
#include "Student.h"
#include <vector>
using namespace std;
class CMFC05Doc : public CDocument
{
protected: // 仅从序列化创建
CMFC05Doc();
DECLARE_DYNCREATE(CMFC05Doc)
// 特性
public:
vector<CStudent> svect;
// 操作
public:
// 重写
public:
virtual BOOL OnNewDocument();
virtual void Serialize(CArchive& ar);
#ifdef SHARED_HANDLERS
virtual void InitializeSearchContent();
virtual void OnDrawThumbnail(CDC& dc, LPRECT lprcBounds);
#endif // SHARED_HANDLERS
// 实现
public:
virtual ~CMFC05Doc();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// 生成的消息映射函数
protected:
DECLARE_MESSAGE_MAP()
#ifdef SHARED_HANDLERS
// 用于为搜索处理程序设置搜索内容的 Helper 函数
void SetSearchContent(const CString& value);
#endif // SHARED_HANDLERS
public:
afx_msg void OnAddStu();
// virtual BOOL OnOpenDocument(LPCTSTR lpszPathName);
};
其中 : vector<CStudent> svect; 即保存多个学生信息的向量(STL)
资源视图中添加菜单命令:
添加对话框(用于添加学生)
文档类中响应菜单命令,并且打开对话框:
代码如下:
// MFC05Doc.cpp : CMFC05Doc 类的实现
//
#include "stdafx.h"
// SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
// ATL 项目中进行定义,并允许与该项目共享文档代码。
#ifndef SHARED_HANDLERS
#include "MFC05.h"
#endif
#include "MFC05Doc.h"
#include <propkey.h>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CMFC05Doc
#include "AddStuDlg.h"
IMPLEMENT_DYNCREATE(CMFC05Doc, CDocument)
BEGIN_MESSAGE_MAP(CMFC05Doc, CDocument)
ON_COMMAND(IDC_ADD_STU, &CMFC05Doc::OnAddStu)
END_MESSAGE_MAP()
// CMFC05Doc 构造/析构
CMFC05Doc::CMFC05Doc()
{
// TODO: 在此添加一次性构造代码
}
CMFC05Doc::~CMFC05Doc()
{
}
BOOL CMFC05Doc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: 在此添加重新初始化代码
// (SDI 文档将重用该文档)
svect.clear();
return TRUE;
}
// CMFC05Doc 序列化
void CMFC05Doc::Serialize(CArchive& ar)
{
int size;
if (ar.IsStoring())
{
// TODO: 在此添加存储代码
size=svect.size();
ar<<size;
for(int i=0;i<size;i++)
svect[i].Serialize(ar);
}
else
{
// TODO: 在此添加加载代码
ar>>size;
for(int i=0;i<size;i++)
{
CStudent s;
s.Serialize(ar);
svect.push_back(s);
}
}
}
#ifdef SHARED_HANDLERS
// 缩略图的支持
void CMFC05Doc::OnDrawThumbnail(CDC& dc, LPRECT lprcBounds)
{
// 修改此代码以绘制文档数据
dc.FillSolidRect(lprcBounds, RGB(255, 255, 255));
CString strText = _T("TODO: implement thumbnail drawing here");
LOGFONT lf;
CFont* pDefaultGUIFont = CFont::FromHandle((HFONT) GetStockObject(DEFAULT_GUI_FONT));
pDefaultGUIFont->GetLogFont(&lf);
lf.lfHeight = 36;
CFont fontDraw;
fontDraw.CreateFontIndirect(&lf);
CFont* pOldFont = dc.SelectObject(&fontDraw);
dc.DrawText(strText, lprcBounds, DT_CENTER | DT_WORDBREAK);
dc.SelectObject(pOldFont);
}
// 搜索处理程序的支持
void CMFC05Doc::InitializeSearchContent()
{
CString strSearchContent;
// 从文档数据设置搜索内容。
// 内容部分应由“;”分隔
// 例如: strSearchContent = _T("point;rectangle;circle;ole object;");
SetSearchContent(strSearchContent);
}
void CMFC05Doc::SetSearchContent(const CString& value)
{
if (value.IsEmpty())
{
RemoveChunk(PKEY_Search_Contents.fmtid, PKEY_Search_Contents.pid);
}
else
{
CMFCFilterChunkValueImpl *pChunk = NULL;
ATLTRY(pChunk = new CMFCFilterChunkValueImpl);
if (pChunk != NULL)
{
pChunk->SetTextValue(PKEY_Search_Contents, value, CHUNK_TEXT);
SetChunkValue(pChunk);
}
}
}
#endif // SHARED_HANDLERS
// CMFC05Doc 诊断
#ifdef _DEBUG
void CMFC05Doc::AssertValid() const
{
CDocument::AssertValid();
}
void CMFC05Doc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
// CMFC05Doc 命令
void CMFC05Doc::OnAddStu()
{
// TODO: 在此添加命令处理程序代码
CAddStuDlg dlg;
if(dlg.DoModal()==IDOK)
{
CStudent stu;
stu.cid=dlg.m_cid;
stu.classname=dlg.m_classname;
stu.department=dlg.m_department;
stu.grade=dlg.m_grade;
stu.major=dlg.m_major;
stu.name=dlg.m_name;
svect.push_back(stu);
this->UpdateAllViews(NULL);
this->SetModifiedFlag();
}
}
核心代码:
1、序列化函数,Serialize
思路:保存的时候,先写入学生个数,然后一个个写,读取的时候正好相反.。CStudent的序列化函数需要好好了解一下;
2、菜单命令响应:
打开对话框,读取添加的数据,新生成一个CStudent,添加到Vector,并且更新视图和设置文档已经修改标记(提醒保存)。
视图类相对比较简单:
// MFC05View.h : CMFC05View 类的接口
//
#pragma once
class CMFC05View : public CListView
{
protected: // 仅从序列化创建
CMFC05View();
DECLARE_DYNCREATE(CMFC05View)
// 特性
public:
CMFC05Doc* GetDocument() const;
// 操作
public:
// 重写
public:
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
bool isInitView;
void InitView();
void InitData();
protected:
virtual void OnInitialUpdate(); // 构造后第一次调用
// 实现
public:
virtual ~CMFC05View();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// 生成的消息映射函数
protected:
DECLARE_MESSAGE_MAP()
public:
// afx_msg void OnPaint();
// afx_msg void OnSize(UINT nType, int cx, int cy);
// virtual void OnUpdate(CView* /*pSender*/, LPARAM /*lHint*/, CObject* /*pHint*/);
// virtual void OnUpdate(CView* /*pSender*/, LPARAM /*lHint*/, CObject* /*pHint*/);
// afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
virtual void OnUpdate(CView* /*pSender*/, LPARAM /*lHint*/, CObject* /*pHint*/);
};
#ifndef _DEBUG // MFC05View.cpp 中的调试版本
inline CMFC05Doc* CMFC05View::GetDocument() const
{ return reinterpret_cast<CMFC05Doc*>(m_pDocument); }
#endif
// MFC05View.cpp : CMFC05View 类的实现
//
#include "stdafx.h"
// SHARED_HANDLERS 可以在实现预览、缩略图和搜索筛选器句柄的
// ATL 项目中进行定义,并允许与该项目共享文档代码。
#ifndef SHARED_HANDLERS
#include "MFC05.h"
#endif
#include "MFC05Doc.h"
#include "MFC05View.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// CMFC05View
IMPLEMENT_DYNCREATE(CMFC05View, CListView)
BEGIN_MESSAGE_MAP(CMFC05View, CListView)
// ON_WM_SIZE()
END_MESSAGE_MAP()
// CMFC05View 构造/析构
CMFC05View::CMFC05View()
{
// TODO: 在此处添加构造代码
isInitView=false;
}
CMFC05View::~CMFC05View()
{
}
BOOL CMFC05View::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: 在此处通过修改
// CREATESTRUCT cs 来修改窗口类或样式
return CListView::PreCreateWindow(cs);
}
void CMFC05View::OnInitialUpdate()
{
CListView::OnInitialUpdate();
if(!isInitView) InitView();
InitData();
}
void CMFC05View::InitView()
{
CListCtrl& m_list = GetListCtrl();//得到内置的listctrl引用
LONG lStyle;
lStyle = GetWindowLong(m_list.m_hWnd, GWL_STYLE);//获取当前窗口风格
lStyle |= LVS_REPORT; //设置报表风格
SetWindowLong(m_list.m_hWnd, GWL_STYLE, lStyle); //设置窗口风格
CRect rect;
m_list.GetClientRect(&rect);
int cx =rect.Width()/8;
m_list.InsertColumn( 0, " ", LVCFMT_CENTER, 50 );
m_list.InsertColumn( 1, "姓名", LVCFMT_CENTER, cx );
m_list.InsertColumn( 2, "学号", LVCFMT_CENTER, cx );
m_list.InsertColumn( 3, "系部", LVCFMT_CENTER, cx );
m_list.InsertColumn( 4, "专业", LVCFMT_CENTER, cx );
m_list.InsertColumn( 5, "年级", LVCFMT_CENTER, cx );
m_list.InsertColumn( 6, "班级", LVCFMT_CENTER, cx );
m_list.InsertColumn( 7, "备注", LVCFMT_CENTER, 2*cx- 50);
isInitView=true;
}
void CMFC05View::InitData()
{
CListCtrl& m_list = GetListCtrl();
m_list.DeleteAllItems();
vector<CStudent> svect=GetDocument()->svect;
for(int i=0;i<svect.size();i++)
{
CString cs;
cs.Format("%d",i+1);
int row=m_list.InsertItem(i, "");
m_list.SetItemText(row, 0, cs);
m_list.SetItemText(row, 1, svect[i].name);
m_list.SetItemText(row, 2, svect[i].cid);
m_list.SetItemText(row, 3, svect[i].department);
m_list.SetItemText(row, 4, svect[i].major);
m_list.SetItemText(row, 5, svect[i].grade);
m_list.SetItemText(row, 6, svect[i].classname);
m_list.SetItemText(row, 7, "");
}
}
// CMFC05View 诊断
#ifdef _DEBUG
void CMFC05View::AssertValid() const
{
CListView::AssertValid();
}
void CMFC05View::Dump(CDumpContext& dc) const
{
CListView::Dump(dc);
}
CMFC05Doc* CMFC05View::GetDocument() const // 非调试版本是内联的
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMFC05Doc)));
return (CMFC05Doc*)m_pDocument;
}
#endif //_DEBUG
void CMFC05View::OnUpdate(CView* /*pSender*/, LPARAM /*lHint*/, CObject* /*pHint*/)
{
// TODO: 在此添加专用代码和/或调用基类
InitData();
}
总结:
1、MFC提供的文档操作框架简化了文件操作,核心是序列化处理数据,由文档类去调用用户自定义的序列化函数,实现特定数据的读写;
2、MFC屏蔽了文件的操作和消息响应,结论是读写文件都会自动调用文档类的Serialize函数,具体流程可以通过跟踪调试去了解(应用程序类首先响应打开、新建、保存文档的消息!)
3、重点掌握三口组(文档、视图、框架)以及应用程序类之间的相互调用:
获取应用程序对象指针:::AfxGetApp() 全局函数 可以强制转换
获取主框架指针:::AfxGetMainWnd() 或者 ::AfxGetApp()->m_pMainWnd; 可以强制转换
视图获取文档:GetDocument() (框架提供)
视图获取主框架还可以:GetParentFrame() 可以强制转换
文档类获取视图:多视图需要枚举(比如窗口分割后多块显示同一个文档)
POSITION pos=CDocument::GetFirstViewPosition();
while(pos != NULL)
{
CView *pView=CDocument::GetNextView(pos);
if(pView->GetRuntimeClass()==RUNTIME_CLASS(C**View))
{
}
}
单视图可以按框架方法来完成。
框架获取视图:
单文档单视图 GetActiveView()
多视图:先获取文档指针 GetActiveDocument() ,然后 枚举(见上)。
4、MFC文档操作相对比较简单安全,当然也可以自己通过CFile等相关类来实现数据文档的操作。