IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> C++知识库 -> MFC文档与视图(笔记) -> 正文阅读

[C++知识库]MFC文档与视图(笔记)

应用程序类包含着一个模板文档的对象。

通过模板文档可生成任意数目文档,用于存放数据。

存储的一个文档的数据可由任意视图来呈现数据。

框架窗口类则可以管理文档类与视图类。

?一、数据的存储与加载

序列化:以二进制方式写文件

反序列化:以二进制方式读文件

使用CArchive类,它没有基类。


创建MFC应用程序,使用单文档,MFC标准。

在资源视图中的菜单中,为其添加如下标签

右击,分别为其添加事件处理

?此处,笔者将消息处理的位置放在框架类

其实现如下

//写文件模式
void CMainFrame::OnCarchiveWrite()
{
	// TODO: 在此添加命令处理程序代码
	CFile file;
	//地址,模式(创建模式,写模式)
	BOOL isDown = file.Open(_T("res/output.txt"),CFile::modeCreate|CFile::modeWrite);
	if (isDown == FALSE) {//操作失败则结束
		return;
	}
	//将CArchive与CFile绑定
	//文件指针,存储
	CArchive ar(&file, CArchive::store);
	int a = 10;
	CString str = _T("ABC");
	ar << a << str;
	ar.Close();
	file.Close();
}

//读文件模式
void CMainFrame::OnCarchiveRead()
{
	// TODO: 在此添加命令处理程序代码
	CFile file;
	//地址,模式(读模式)
	BOOL isDown = file.Open(_T("res/output.txt"),CFile::modeRead);
	if (isDown == FALSE) {//操作失败则结束
		return;
	}
	//将CArchive与CFile绑定
	//文件指针,加载
	CArchive ar(&file, CArchive::load);
	DATE date;//获取时间
	int a;
	CString str;
	ar >> a >>str;
	str.Format(_T("%d,%s"), a, str);
	MessageBox(str);
	ar.Close();
	file.Close();
}

二、文档类的序列化函数

?通过类视图可以快速转到文档类的Serialize函数

?先将其修改

void CMFCApplication1Doc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO:  在此添加存储代码
		//点击保存时被调用
		CString str = _T("test");
		int a = 250;
		ar << str << a;
	}
	else
	{
		// TODO:  在此添加加载代码
		//打开文件时被调用
		CString str;
		int a;
		ar >> str >> a;
		str.Format(_T("%d,%s"), a, str);
		//要使用全局的,因为没有MessageBox
		AfxMessageBox(str);
	}
}

?运行,先点击保存按钮任意命名(因为以二级制模式读写),然后再通过打开按钮打开。

三、?存储绘图以模拟事务的保存

?为文档类新增如下成员变量,为方便设为public

	//设置最大可存储200个绘图点的数组
	CPoint m_pt[200];
	//记录当前绘制的点是第几个点
	int num;

?注意OnNewDocument是每新建一个文档就会调用一次。

(程序刚开始运行时,和新建文档按钮按下时被调用)

同时DeleteContents则是每一次新建前会被调用(是一个虚函数,通过重写列表可以找到)

类似于析构函数。


现将析构函数重写,用于初始化(因为Delete最先执行,当然也可以在new里面)

void CMFCApplication1Doc::DeleteContents()
{
	// TODO: 在此添加专用代码和/或调用基类
	//将m_pt初始化
	//地址,初始化值,每一个的大小
	memset(&m_pt, 0, sizeof(m_pt));
	num = 0;
	CDocument::DeleteContents();
}

然后为视图添加左键点击事件

void CMFCApplication1View::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	//获取文档类指针
	CMFCApplication1Doc* pDoc = GetDocument();
	if (pDoc->num > 199) {//超过则禁止
		MessageBox(_T("不能超过200个点"));
		return;
	}
	pDoc->m_pt[pDoc->num] = point;
	pDoc->num++;
	//窗口失效,即调用OnDraw函数重绘页面
	Invalidate();
	CView::OnLButtonDown(nFlags, point);
}

?在转到View的绘图函数

void CMFCApplication1View::OnDraw(CDC* pDC)
{
	CMFCApplication1Doc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;
	
	// TODO: 在此处为本机数据添加绘制代码
	for (int i = 0;i < pDoc->num;i++) {
		//将点击位置设置为圆
		pDC->Ellipse(pDoc->m_pt[i].x - 5,pDoc->m_pt[i].y-5,pDoc->m_pt[i].x+5,pDoc->m_pt[i].y+5);
	}
}

结果如下?

现在开始保存数据,转到文档类的Serialize函数


void CMFCApplication1Doc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO:  在此添加存储代码
        //存储
		ar << num;
		for (int i = 0;i < num;i++) {
			ar << m_pt[i];
		}

	}
	else
	{
		// TODO:  在此添加加载代码
        //加载
		ar >> num;
		for (int i = 0;i < num;i++) {
			ar >> m_pt[i];
		}
	}
}

四、文档视图案例?

通过文档与视图合作,对学生信息进行查询。

本案例的数据存储在MFC的链表之中,而不是在数据库。

使用单文档,MFC标准。

以及修改View的基类,该方式使得View支持控件。

(若报“没有对CForm的打印支持”等错误,可能是组件不全,但本案例用不到,可以无视。)

?在设计页面为该View添加如下控件

记得将“编辑”单选框的Group设为true。并注意单选框的顺序时连着的("ctrl+D"查看)

为“上一个”按钮与“下一个”以及”添加“按钮,添加控制变量。

?现在双击,为其添加点击事件。

另外在View类中,为其创建一个privatebool变量flag,用于判断当前状态(编辑还是预览)

//编辑模式
void CStudentInfoView::OnBnClickedRadio1()
{
	// TODO: 在此添加控件通知处理程序代码
	m_Pre.EnableWindow(FALSE);
	m_Next.EnableWindow(FALSE);
	flag = false;
	m_add.SetWindowTextW(_T("修改"));
}

//预览模式
void CStudentInfoView::OnBnClickedRadio2()
{
	// TODO: 在此添加控件通知处理程序代码
	m_Pre.EnableWindow(TRUE);
	m_Next.EnableWindow(TRUE);
	flag = true;
	m_add.SetWindowTextW(_T("添加"));
}

?随后设置默认选中项(在ViewForm中,我们可以在OnInitialUpddate处初始化)


void CStudentInfoView::OnInitialUpdate()
{
	CFormView::OnInitialUpdate();
	GetParentFrame()->RecalcLayout();
	ResizeParentToFit();
	//第一个单选框,第二个单选框,默认选中
	CheckRadioButton(IDC_RADIO1, IDC_RADIO2, IDC_RADIO1);
	//调用第一个单选框的点击事件
	OnBnClickedRadio1();

}

结果

?

现在为数据存储做准备。?

通过资源管理器添加新的类

?大致建一个就好了

#pragma once

class Student{
public:
	Student(int id,CString name,int age,int score);
	~Student();

	int getId();
	CString getName();
	int getAge();
	int getScore();

	void setId(int id);
	void setName(CString name);
	void setAge(int age);
	void setScore(int score);
private:
	int id;
	CString name;
	int age;
	int score;

};
#include "pch.h"
#include "Student.h"

Student::Student(int id, CString name, int age, int score){
	this->id = id;
	this->name = name;
	this->age = age;
	this->score = score;
}

Student::~Student() {


}

int Student::getId()
{
	return this->id;
}

CString Student::getName()
{
	return this->name;
}

int Student::getAge()
{
	return this->age;
}

int Student::getScore()
{
	return this->score;
}

void Student::setId(int id)
{
	this->id = id;
}

void Student::setName(CString name)
{
	this->name = name;
}

void Student::setAge(int age)
{
	this->age = age;
}

void Student::setScore(int score)
{
	this->score = score;
}

?接着在文档类中导入该类,然后为为文档类添加如下成员变量

public:
	CList<Student*>m_list;//MFC的列表容器
	POSITION m_pos;//当前位置节点,类似于迭代器

?接着为所有文本编辑框准备之变量。

??而后为“添加”、"上一个"、”下一个“按钮添加点击事件。

//添加/修改
void CStudentInfoView::OnBnClickedButton1()
{
	// TODO: 在此添加控件通知处理程序代码
	//编辑区数据更新到后台
	UpdateData(TRUE);
	if (m_Uid == 0 || m_Uname.IsEmpty()|| m_Uage == 0) {
		MessageBox(_T("请注意学号、名称以及年龄不能为空"));
		return;
	}
	//获取文档对象指针
	CStudentInfoDoc* pDoc = GetDocument();
	if (flag == true || pDoc->m_list.GetCount() == 0) {
		Student* student = new Student(m_Uid, m_Uname, m_Uage, m_Uscore);
		//此处直接插入尾部
		pDoc->m_list.AddTail(student);
		//获取最后一个节点
		pDoc->m_pos = pDoc->m_list.GetTailPosition();
	}
	else{
		Student* stu = pDoc->m_list.GetAt(pDoc->m_pos);
		stu->setId(m_Uid);
		stu->setName(m_Uname);
		stu->setAge(m_Uage);
		stu->setScore(m_Uscore);
	}
}
//上一个
void CStudentInfoView::OnBnClickedButton2()
{
	// TODO: 在此添加控件通知处理程序代码
	//获取文档对象指针
	CStudentInfoDoc* pDoc = GetDocument();
	if (pDoc->m_list.GetCount() == 0) {
		return;
	}
	//获取上一个元素
	//该方式会让m_pos前移,但返回的时移动前的值
	pDoc->m_list.GetPrev(pDoc->m_pos);
	if (pDoc->m_pos == NULL) {//移动到头部时
		//设置尾部节点
		pDoc->m_pos = pDoc->m_list.GetTailPosition();
	}
	//获取当前位置的元素
	Student* student = pDoc->m_list.GetAt(pDoc->m_pos);
	m_Uid = student->getId();
	m_Uname = student->getName();
	m_Uage = student->getAge();
	m_Uscore = student->getScore();
	//更新到编辑区
	UpdateData(FALSE);
}
//下一个
void CStudentInfoView::OnBnClickedButton3()
{
	// TODO: 在此添加控件通知处理程序代码
	//获取文档对象指针
	CStudentInfoDoc* pDoc = GetDocument();
	if (pDoc->m_list.GetCount() == 0) {
		return;
	}
	//获取上一个元素
	//该方式会让m_pos前移,但返回的时移动前的值
	pDoc->m_list.GetNext(pDoc->m_pos);
	if (pDoc->m_pos == NULL) {//移动到头部时
		//设置尾部节点
		pDoc->m_pos = pDoc->m_list.GetHeadPosition();
	}
	//获取当前位置的元素
	Student* student = pDoc->m_list.GetAt(pDoc->m_pos);
	m_Uid = student->getId();
	m_Uname = student->getName();
	m_Uage = student->getAge();
	m_Uscore = student->getScore();
	//更新到编辑区
	UpdateData(FALSE);
}

最后再在文档类中重写DeleteContents,来清空数据

void CStudentInfoDoc::DeleteContents()
{
	// TODO: 在此添加专用代码和/或调用基类
	//该方法可以直接释放所占用空间
	m_list.RemoveAll();
	CDocument::DeleteContents();
}

通过其底层可知,该方法调用了析构函数 ,直接调用每一个节点的析构函数。

此外,用RemoveHead从头部一项一项移除也是可以的,但不需要用一个类去接收其返回值,因为它返回的是一个值,而不是一个动态分配的地址(new),不接收会自动回收。

?

  C++知识库 最新文章
【C++】友元、嵌套类、异常、RTTI、类型转换
通讯录的思路与实现(C语言)
C++PrimerPlus 第七章 函数-C++的编程模块(
Problem C: 算法9-9~9-12:平衡二叉树的基本
MSVC C++ UTF-8编程
C++进阶 多态原理
简单string类c++实现
我的年度总结
【C语言】以深厚地基筑伟岸高楼-基础篇(六
c语言常见错误合集
上一篇文章      下一篇文章      查看所有文章
加:2021-10-09 16:05:38  更:2021-10-09 16:06:55 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/29 19:13:39-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码
数据统计