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.