MFC documents and views (notes)

The application class contains the object of a template document.

Any number of documents can be generated through template documents to store data.

The data of a stored document can be presented by any view.

Frame window class can manage document class and view class.

  1, Data storage and loading

Serialization: writing files in binary mode

Deserialization: reading files in binary mode

Use the carrchive class, which has no base class.

Create MFC application, using single document, MFC standard.

In the menu in the resource view, add the following label to it

Right click to add event handling respectively

  Here, the author puts the location of message processing in the framework class

Its implementation is as follows

//Write file mode
void CMainFrame::OnCarchiveWrite()
{
	// TODO: add command handler code here
	CFile file;
	//Address, mode (create mode, write mode)
	BOOL isDown = file.Open(_T("res/output.txt"),CFile::modeCreate|CFile::modeWrite);
	if (isDown == FALSE) {//The operation ends if it fails
		return;
	}
	//Bind the carrchive to CFile
	//File pointer, storage
	CArchive ar(&file, CArchive::store);
	int a = 10;
	CString str = _T("ABC");
	ar << a << str;
	ar.Close();
	file.Close();
}

//Read file mode
void CMainFrame::OnCarchiveRead()
{
	// TODO: add command handler code here
	CFile file;
	//Address, mode (read mode)
	BOOL isDown = file.Open(_T("res/output.txt"),CFile::modeRead);
	if (isDown == FALSE) {//The operation ends if it fails
		return;
	}
	//Bind the carrchive to CFile
	//File pointer, loading
	CArchive ar(&file, CArchive::load);
	DATE date;//Get time
	int a;
	CString str;
	ar >> a >>str;
	str.Format(_T("%d,%s"), a, str);
	MessageBox(str);
	ar.Close();
	file.Close();
}

2, Serialization function of document class

  The class view allows you to quickly go to the Serialize function of the document class

  Modify it first

void CMFCApplication1Doc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: add storage code here
		//Called when clicking save
		CString str = _T("test");
		int a = 250;
		ar << str << a;
	}
	else
	{
		// TODO: add load code here
		//Called when opening a file
		CString str;
		int a;
		ar >> str >> a;
		str.Format(_T("%d,%s"), a, str);
		//Use global because there is no MessageBox
		AfxMessageBox(str);
	}
}

  To run, first click the Save button to name it arbitrarily (because it is read and written in the secondary system mode), and then open it through the open button.

III   Store drawings to simulate the saving of transactions

  Add the following member variables to the document class and set them to public for convenience

	//Set an array that can store up to 200 drawing points
	CPoint m_pt[200];
	//Record the number of points currently drawn
	int num;

  Note that OnNewDocument is called every time a new document is created.

(called when the program starts running and when the new document button is pressed)

Meanwhile, DeleteContents is called before each new creation (a virtual function, which can be found by rewriting the list)

Similar to destructors.

Now rewrite the destructor for initialization (because Delete is executed first, of course, it can also be in new)

void CMFCApplication1Doc::DeleteContents()
{
	// TODO: add special code and / or call base class here
	//Will m_pt initialization
	//Address, initialization value, size of each
	memset(&m_pt, 0, sizeof(m_pt));
	num = 0;
	CDocument::DeleteContents();
}

Then add a left click event to the view

void CMFCApplication1View::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: add message handler code here and / or call default values
	//Get document class pointer
	CMFCApplication1Doc* pDoc = GetDocument();
	if (pDoc->num > 199) {//No more than
		MessageBox(_T("No more than 200 points"));
		return;
	}
	pDoc->m_pt[pDoc->num] = point;
	pDoc->num++;
	//If the window fails, the OnDraw function is called to redraw the page
	Invalidate();
	CView::OnLButtonDown(nFlags, point);
}

  Go to the drawing function in View

void CMFCApplication1View::OnDraw(CDC* pDC)
{
	CMFCApplication1Doc* pDoc = GetDocument();
	ASSERT_VALID(pDoc);
	if (!pDoc)
		return;
	
	// TODO: add drawing code for native data here
	for (int i = 0;i < pDoc->num;i++) {
		//Set the click position to circle
		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);
	}
}

give the result as follows  

Now to save the data, go to the Serialize function of the document class

void CMFCApplication1Doc::Serialize(CArchive& ar)
{
	if (ar.IsStoring())
	{
		// TODO: add storage code here
        //storage
		ar << num;
		for (int i = 0;i < num;i++) {
			ar << m_pt[i];
		}

	}
	else
	{
		// TODO: add load code here
        //load
		ar >> num;
		for (int i = 0;i < num;i++) {
			ar >> m_pt[i];
		}
	}
}

4, Document view case  

Query the student information through the cooperation of document and view.

The data of this case is stored in the linked list of MFC, not in the database.

Use single document, MFC standard.

And modify the base class of View, which makes View support controls.

(if an error such as "no printing support for CForm" is reported, it may be that the components are incomplete, but it can not be used in this case, so it can be ignored.)

  Add the following controls for the View on the design page

Remember to set the Group of the edit radio box to true. Note the order of the radio boxes (ctrl+D)

Add control variables for the previous and Next buttons and the Add button.

  Now double-click to add a click event.

In addition, in the View class, create a private bool variable flag for it to judge the current state (edit or preview)

//Edit mode
void CStudentInfoView::OnBnClickedRadio1()
{
	// TODO: add control notification handler code here
	m_Pre.EnableWindow(FALSE);
	m_Next.EnableWindow(FALSE);
	flag = false;
	m_add.SetWindowTextW(_T("modify"));
}

//Preview Mode 
void CStudentInfoView::OnBnClickedRadio2()
{
	// TODO: add control notification handler code here
	m_Pre.EnableWindow(TRUE);
	m_Next.EnableWindow(TRUE);
	flag = true;
	m_add.SetWindowTextW(_T("add to"));
}

  Then set the default check item (in ViewForm, we can initialize at oninitialupdate)

void CStudentInfoView::OnInitialUpdate()
{
	CFormView::OnInitialUpdate();
	GetParentFrame()->RecalcLayout();
	ResizeParentToFit();
	//The first radio box and the second radio box are selected by default
	CheckRadioButton(IDC_RADIO1, IDC_RADIO2, IDC_RADIO1);
	//Call the click event of the first radio box
	OnBnClickedRadio1();

}

result

 

Now prepare for data storage.  

Add a new class through Explorer

  Just build one roughly

#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;
}

  Then import the class in the document class, and then add the following member variables for the document class

public:
	CList<Student*>m_list;//List container for MFC
	POSITION m_pos;//The current location node, similar to an iterator

  Then prepare variables for all text edit boxes.

   Then add click events for the "add", "previous" and "next" buttons.

//Add / modify
void CStudentInfoView::OnBnClickedButton1()
{
	// TODO: add control notification handler code here
	//Edit area data update to background
	UpdateData(TRUE);
	if (m_Uid == 0 || m_Uname.IsEmpty()|| m_Uage == 0) {
		MessageBox(_T("Please note that student number, name and age cannot be blank"));
		return;
	}
	//Get document object pointer
	CStudentInfoDoc* pDoc = GetDocument();
	if (flag == true || pDoc->m_list.GetCount() == 0) {
		Student* student = new Student(m_Uid, m_Uname, m_Uage, m_Uscore);
		//Insert tail directly here
		pDoc->m_list.AddTail(student);
		//Get last node
		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);
	}
}
//the previous
void CStudentInfoView::OnBnClickedButton2()
{
	// TODO: add control notification handler code here
	//Get document object pointer
	CStudentInfoDoc* pDoc = GetDocument();
	if (pDoc->m_list.GetCount() == 0) {
		return;
	}
	//Get previous element
	//This method causes m_pos to move forward, but returns the value before moving
	pDoc->m_list.GetPrev(pDoc->m_pos);
	if (pDoc->m_pos == NULL) {//When moving to the head
		//Set tail node
		pDoc->m_pos = pDoc->m_list.GetTailPosition();
	}
	//Gets the element of the current location
	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();
	//Update to edit area
	UpdateData(FALSE);
}
//next
void CStudentInfoView::OnBnClickedButton3()
{
	// TODO: add control notification handler code here
	//Get document object pointer
	CStudentInfoDoc* pDoc = GetDocument();
	if (pDoc->m_list.GetCount() == 0) {
		return;
	}
	//Get previous element
	//This method causes m_pos to move forward, but returns the value before moving
	pDoc->m_list.GetNext(pDoc->m_pos);
	if (pDoc->m_pos == NULL) {//When moving to the head
		//Set tail node
		pDoc->m_pos = pDoc->m_list.GetHeadPosition();
	}
	//Gets the element of the current location
	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();
	//Update to edit area
	UpdateData(FALSE);
}

Finally, override DeleteContents in the document class to empty the data

void CStudentInfoDoc::DeleteContents()
{
	// TODO: add special code and / or call base class here
	//This method can directly release the occupied space
	m_list.RemoveAll();
	CDocument::DeleteContents();
}

From its bottom layer, it can be seen that the method calls the destructor and directly calls the destructor of each node.

In addition, it is also possible to remove the header item by item with RemoveHead, but it is not necessary to use a class to receive its return value, because it returns a value rather than a dynamically allocated address (new). If it is not received, it will be automatically recycled.

 

Tags: MFC

Posted on Fri, 08 Oct 2021 05:42:07 -0400 by shu