1 文档视图案例的初始化
1)创建基于单文档的MFC程序,但是到下图步骤时,需要换一下视图的继承基类为CFormView。。
这样下面我们就多出了FORM这个对话框,以前单文档继承于CView时是没有对话框的,所以无法操作控件。
2)然后按如下所示添加控件。其中模式为GroupBox容器,需要注意Group里面的ID顺序。
3)将Group第一个控件即编辑单选框的Group属性置为true。
4)然后将上一个下一个这两个按钮添加变量。
5)这里将编辑模式时,上一个,下一个这两个按钮为灰色,预览模式时为高亮。所以分别双击编辑和预览按钮,去到响应函数。
void CanliView::OnBnClickedRadio1()
{
// TODO: 在此添加控件通知处理程序代码
m_buttonPre.EnableWindow(FALSE);
m_buttonNext.EnableWindow(FALSE);
}
void CanliView::OnBnClickedRadio2()
{
// TODO: 在此添加控件通知处理程序代码
m_buttonPre.EnableWindow(TRUE);
m_buttonNext.EnableWindow(TRUE);
}
6)由于我们设定默认是编辑模式,所以当我们没有按下单选框也要为灰色,所以需要在视图的初始化函数OnInitialUpdate初始化上一个下一个按钮为灰色。
void CanliView::OnInitialUpdate()
{
CFormView::OnInitialUpdate();
GetParentFrame()->RecalcLayout();
ResizeParentToFit();
CheckRadioButton(IDC_RADIO1, IDC_RADIO2, IDC_RADIO1);//设置编辑区默认显示
m_buttonPre.EnableWindow(FALSE);
m_buttonNext.EnableWindow(FALSE);
}
初始化后的结果:
2 文档视图案例的实现
先了解相关函数。
1)新建一个学生类。
#pragma once
class Student
{
public:
Student(int id, CString name, int age, int score);
virtual ~Student();
public:
int m_id;
CString m_name;
int m_age;
int m_score;
};
Student::Student(int id, CString name, int age, int score)
{
m_id = id;
m_name = name;
m_age = age;
m_score = score;
}
Student::~Student()
{
}
2)在文档类Doc添加链表成员,用于保存数据。因为MFC的链表需要保存当前节点位置,所以也要添加一个保存当前节点位置的变量。
CList<Student*> m_list;
POSITION m_pos;
3)为四个编辑区关联Value类型的变量。
4)双击添加按钮,去到响应函数处理。
//添加按钮
void CanliView::OnBnClickedButton1()
{
// TODO: 在此添加控件通知处理程序代码
//1 更新内容到变量
UpdateData(TRUE);
//2 创建学生信息
Student *stu = new Student(m_uiId, m_uiName, m_uiAge, m_uiScore);
//3 保存到链表
CanliDoc *pDoc = GetDocument();
pDoc->m_list.AddTail(stu);
//4 更新当前节点为新添加的节点
pDoc->m_pos = pDoc->m_list.GetTailPosition();
}
5)双击上一个按钮,去到响应函数处理。
/上一个按钮
void CanliView::OnBnClickedButton2()
{
// TODO: 在此添加控件通知处理程序代码
//1 获取上一节点下标
CanliDoc *pDoc = GetDocument();
if (pDoc->m_list.GetSize() <= 0) {
return;
}
pDoc->m_list.GetPrev(pDoc->m_pos);//自动将m_pos指向上一节点
if (pDoc->m_pos == NULL) {
pDoc->m_pos = pDoc->m_list.GetTailPosition();//如果指向头结点前面的NULL,就重新指向末尾
}
//2 通过上一节点下标获取上一节点元素
Student *tmp = pDoc->m_list.GetAt(pDoc->m_pos);
//3 更新值到编辑区
m_uiId = tmp->m_id;
m_uiName = tmp->m_name;
m_uiAge = tmp->m_age;
m_uiScore = tmp->m_score;
UpdateData(FALSE);
}
6)双击下一个按钮,去到响应函数处理。
//下一个按钮
void CanliView::OnBnClickedButton3()
{
// TODO: 在此添加控件通知处理程序代码
//1 获取下一节点下标
CanliDoc *pDoc = GetDocument();
if (pDoc->m_list.GetSize() <= 0) {
return;
}
pDoc->m_list.GetNext(pDoc->m_pos);
if (pDoc->m_pos == NULL) {
pDoc->m_pos = pDoc->m_list.GetHeadPosition();
}
//2 通过下一节点下标获取下一节点元素
Student *tmp = pDoc->m_list.GetAt(pDoc->m_pos);
//3 更新值到编辑区
m_uiId = tmp->m_id;
m_uiName = tmp->m_name;
m_uiAge = tmp->m_age;
m_uiScore = tmp->m_score;
UpdateData(FALSE);
}
7)由于每次新建文档都需要释放上一次的内容,所以我们需要重写文档类的DeleteContents函数。
void CanliDoc::DeleteContents()
{
// TODO: 在此添加专用代码和/或调用基类
while (m_list.GetHeadPosition() != NULL) {
Student *tmp = m_list.RemoveHead();//只剔除出链表,并不会释放空间
delete tmp;
tmp = NULL;
}
m_pos = NULL;
CDocument::DeleteContents();
}
至此本案例结束,但是该案例可能会存在部分bug,自己维护一下即可。下图几个键额度功能都实现了。