MFC - 課程設計 - 學生成績管理系統(帶直方圖/折線圖數據顯示)

如題

********菜雞的課設,僅供交流參考
在這裏插入圖片描述

在這裏插入圖片描述
(2)程序功能模塊的設計
1.學生管理系統的實現:
在我的程序裏,MFC主對話框“學生管理系統”中擁有“保存”,“打開”,“添加”,“刪除”,“按高數成績排序”,“按C++成績排序”,“修改”,“確定”,“反選”一共9個按鈕,以及“學號”,“姓名”,“高數”,“C++”四個編輯框,還有一個list control列表用於顯示數據。四個編輯框綁定了4個CString變量,利於直接獲取數據,
在students managementDlg.cpp中擁有list control初始化的代碼以及8個按鈕分別對應實現的代碼。在student.h頭文件,裏面用於存放一個“學生類”,在public中存放學生的姓名,學號,高數成績,c++成績,(分CString以及long long)兩個類型存儲,用一個convert成員函數實現從CString數據轉變爲long long存儲以便實現排序功能。
在manageff.h頭文件中,存放一個用於管理“學生類”的“管理類”,在private中存儲len(管理學生的容器總大小),count(已存學生數量),public中實現構造函數(初始化),學生類指針(容器),獲取容器大小的函數getcount,向容器中添加學生的函數add,指定位置刪除容器中的學生函數del,根據高數成績排序的函數math_sort,根據c++成績排序的函數Cjj_sort以及判斷容器中是否有相同學號的人的函數getsame(實現當添加時容器中已存在學號相同的學生則無法添加的功能)
在mangement.cpp中實現“學生類”以及“管理類”中的函數。

2.數據用直方圖以及折線圖顯示的實現:
在MFC單文檔中的View.h的類CView的public添加兩個按鈕CButton函數以及一個函數Open。在View.cpp中的OnDraw函數裏實現的繪圖,在類嚮導中添加一個OnCreate函數,並且實現按鈕的顯示。最後實現兩個按鈕的函數(打開“學生管理系統”中保存的save.txt,根據提取save.txt中的數據更改各個分段的高度以顯示出直方圖以及折現圖)。

(3)帶有詳細註釋的自己編寫的關鍵源程序:
1.學生管理系統:

//將四個編輯框分別綁定四個CString變量:Id,name,math,Cjj

1.Student.h頭文件:

#include <afxtempl.h>
#define ll long long
using namespace std;
#pragma once

class student
{
public:
	//除了name以外所有數據均存一份CString跟一份long long
	ll Idq;
	ll mathq;
	ll Cjjq;
	CString name;//姓名
	CString Id;//學號
	CString math;//高數成績
	CString Cjj;//C++成績
	void convert();//將存儲的CString轉換成long long
};

2.Manageff.h頭文件:

#pragma once
#include "stdafx.h"
#include "Student.h"

class studentmanag
{
	//學生類數組容器類
private:
	int len;//容器總大小
	int count;//容器已存的大小

public:
	studentmanag();//構造函數
	student * group;//學生數組容器

	int getcount();//獲取容器已存大小
	void add(student x);//向容器添加一個學生
	void del(int x);//從容器中選擇刪除一個學生
	void math_sort();//按高數成績排序數組
	void Cjj_sort();//按C++成績排序數組
	bool getsame(student a);//判斷容器中是否有學號相同的人
};

3.Management.cpp:

#include "stdafx.h"
#include "Student.h"
#include "manageff.h"
#include <algorithm>

using namespace std;

void student::convert()
{
	//將CString轉成long long型存儲
	Idq = _ttoi(Id);
	mathq = _ttoi(math);
	Cjjq = _ttoi(Cjj);
	return;
}

studentmanag::studentmanag()
{
	//初始化
	group = new student[100];
	len = 100;
	count = 0;
}

int studentmanag::getcount()
{
	//獲取容器已存大小
	return this->count;
}

void studentmanag::add(student x)
{
	//容器添加操作
	count++;
	if (count >= len)//如果現有大小等於容器大小,則擴大容器
	{
		student *p = new student[len + 10];//開闢新容器
		len += 10;
		for (int i = 0; i < count - 1; i++)//將新容器複製舊容器
		{
			p[i] = group[i];
		}
		delete[]group;//刪除舊容器的空間
		group = p;//綁定新容器
	}
	group[count - 1] = x;
	return;
}

void studentmanag::del(int x)
{
	//容器刪除操作
	count--;
	int times = count - x;
	while (times--)
	{
		group[x] = group[x + 1];
		x++;
	}
	return;
}

bool cmp1(student x, student y)
{
	//用於排序高數成績的cmp
	if (x.mathq == y.mathq)
	{
		return x.Cjjq > y.Cjjq;
	}
	return x.mathq > y.mathq;
}

void studentmanag::math_sort()
{
	//按高數成績排序
	sort(group, group + count, cmp1);
	return;
}

bool cmp2(student x, student y)
{
	//用於排序c++成績的cmp
	if (x.Cjjq == y.Cjjq)
	{
		return x.mathq > y.mathq;
	}
	return x.Cjjq > y.Cjjq;
}

void studentmanag::Cjj_sort()
{
	//按C++成績排序
	sort(group, group + count, cmp2);
	return;
}

bool studentmanag::getsame(student a)
{
	//判斷容器中是否存在學號相同的人
	ll num = a.Idq;
	bool flag = 0;
	for (int i = 0; i < count; i++)
	{
		if (this->group[i].Idq == num)
		{
			flag = 1;
			break;
		}
	}
	return flag;
}

4.students managementDlg.cpp中關鍵源代碼:
OnInitDialog函數中添加:

//這是listcontrol的初始化,初始化添加勾選框
	m_list.SetExtendedStyle(LVS_EX_FULLROWSELECT|LVS_EX_CHECKBOXES);
	m_list.InsertColumn(0, _T("學號"),0,80);
	m_list.InsertColumn(1, _T("姓名"),0, 80);
	m_list.InsertColumn(2, _T("高數成績"),0, 99);
	m_list.InsertColumn(3, _T("C++成績"),0, 97);

按鈕實現:

 void CstudentsmanageDlg::OnBnClickedButton3()
{
	//添加按鈕

	UpdateData(TRUE);
	//將編輯框中的數據寫入學生類
	student a;
	a.Cjj = Cjj;
	a.Id = Id;
	a.math = math;
	a.name = name;
	a.convert();

	if (stdmanag.getsame(a))
	{
		CString k = "學號重複了!";
		MessageBox(k);
		//彈出信息框k
	}
	else
	{
		stdmanag.add(a);//將該學生加入容器中

		//將數據在列表中顯示出來
		int ncount = m_list.GetItemCount();
		m_list.InsertItem(ncount, a.Id);
		m_list.SetItemText(ncount, 1, a.name);
		m_list.SetItemText(ncount, 2, a.math);
		m_list.SetItemText(ncount, 3, a.Cjj);
	}
}

void CstudentsmanageDlg::OnBnClickedButton2()
{
	//刪除按鈕

	for (int i = 0; i < m_list.GetItemCount(); i++)
	{
		//判斷是否勾選
		BOOL check = m_list.GetCheck(i);
		if (check)
		{
			stdmanag.del(i);
			//調用刪除函數
			m_list.DeleteItem(i);
			//刪除列表中該行數據
			i--;
		}
	}
}

void CstudentsmanageDlg::OnBnClickedButton1()
{
	//修改按鈕

	for (int i = 0; i < m_list.GetItemCount(); i++)
	{
		BOOL check = m_list.GetCheck(i);
		if (check)
		{
			//如果勾選了該項
			UpdateData(TRUE);

			student a;
			a.Cjj = Cjj;
			a.Id = Id;
			a.math = math;
			a.name = name;
			a.convert();
			stdmanag.group[i] = a;
			//根據編輯框中數據更新容器中學生數據

			int ncount = m_list.GetItemCount();
			m_list.SetItemText(i, 0, a.Id);
			m_list.SetItemText(i, 1, a.name);
			m_list.SetItemText(i, 2, a.math);
			m_list.SetItemText(i, 3, a.Cjj);
			//更新列表數據顯示
		}
	}
}

void CstudentsmanageDlg::OnBnClickedButton4()
{
	//按高數成績排序按鈕

	int count = stdmanag.getcount();
	stdmanag.math_sort();
	//調用排序

	m_list.DeleteAllItems();
	//刪除所有列表中所有數據
	for (int i = 0; i < count; i++)
	{
		//容器中所有容器數據添加進列表
		m_list.InsertItem(i, stdmanag.group[i].Id);
		m_list.SetItemText(i, 1, stdmanag.group[i].name);
		m_list.SetItemText(i, 2, stdmanag.group[i].math);
		m_list.SetItemText(i, 3, stdmanag.group[i].Cjj);
	}
}

void CstudentsmanageDlg::OnBnClickedButton5()
{
	//按C++成績排序按鈕

	int count = stdmanag.getcount();
	stdmanag.Cjj_sort();
	//調用排序

	m_list.DeleteAllItems();
	//刪除所有列表中所有數據

	for (int i = 0; i < count; i++)
	{
		//容器中所有容器數據添加進列表
		m_list.InsertItem(i, stdmanag.group[i].Id);
		m_list.SetItemText(i, 1, stdmanag.group[i].name);
		m_list.SetItemText(i, 2, stdmanag.group[i].math);
		m_list.SetItemText(i, 3, stdmanag.group[i].Cjj);
	}
}

void CstudentsmanageDlg::OnBnClickedButton7()
{
	//打開按鈕

	CFileDialog saveDlg(TRUE, ".txt", "save", OFN_OVERWRITEPROMPT, "文本文檔(*.txt)|*.txt|所有文件(*.*)|*.*||", NULL);
	//設置保存文件對話框格式
	
	if (saveDlg.DoModal() == IDOK)
	{
		//如果按了保存

		//獲取文件路徑,並且設置只讀
		CString path = saveDlg.GetPathName();
		CStdioFile file(path, CFile::modeRead);

		CString date;
		student ui;
		int i = 0, j = 0;

		while (file.ReadString(date))//當還能讀取到數據時
		{
			//將數據顯示在列表中
			if (i % 4 == 0)
			{
				m_list.InsertItem(j, date);
			}
			else
			{
				m_list.SetItemText(j, i % 4, date);
			}

			//將數據添加進容器
			if (i % 4 == 0)
			{
				//第一行爲學號
				if (j != 0)
				{
					//除了第一個數據之外,當爲4倍數時即說明ui已獲取完一個學生數據
					//然後添加進容器
					ui.convert();
					stdmanag.add(ui);
				}
				ui.Id = date;
			}
			else if (i % 4 == 1)
			{
				//第二行爲姓名
				ui.name = date;
			}
			else if (i % 4 == 2)
			{
				//第三行爲高數成績
				ui.math = date;
			}
			else if (i % 4 == 3)
			{
				//第四行爲C++成績
				ui.Cjj = date;
			}
			i++;
			if (i % 4 == 0) j++;
			//四個數據一換行
		}
		//將最後一個數據傳進容器
		ui.convert();
		stdmanag.add(ui);
	}
}

void CstudentsmanageDlg::OnBnClickedButton8()
{
	//保存按鈕

	CFileDialog saveDlg(FALSE, ".txt", "save", OFN_OVERWRITEPROMPT, "文本文檔(*.txt)|*.txt|所有文件(*.*)|*.*||", NULL);
	//設置保存文件對話框格式

	if (saveDlg.DoModal() == IDOK)
	{
		//如果按了保存

		CString path = saveDlg.GetPathName();//獲取文件路徑
		CString k = "文件已保存在路徑";
		CString k2;
		k2.Format("%s%s", k, path);//k+k2
		MessageBox(k2);
		//彈出信息框k2

		CStdioFile file(path,CFile::modeWrite|CFile::modeCreate);
		//創建或者寫入文件
		
		//保存數據
		CString cs, hh = "\n";
		for (int i = 0; i < m_list.GetItemCount(); i++)
		{
			//i行
			for (int j = 0; j < 4; j++)
			{
				//j列
				cs = m_list.GetItemText(i, j);
				file.WriteString(cs);
				//寫入一個數據
				file.WriteString(hh);
				//換行
			}
		}
		file.Close();
		//關閉文件
	}
}


void CstudentsmanageDlg::OnBnClickedButton9()
{
	//反選按鈕
	for (int i = 0; i < m_list.GetItemCount(); i++)
	{
		m_list.SetCheck(i, !m_list.GetCheck(i));//設置是否勾中
	}
}

2.直方圖以及折線圖的顯示:

在Doc.cpp中的OnNewDocument函數中添加以下代碼(修改標題)

SetTitle(_T("直方圖/折線圖實現"));

1.在View.h中的Cview類的public添加以下代碼:

afx_msg void OnClickButton1();
afx_msg void OnClickButton2();
//定義按鈕1,2	
CButton m_button;
CButton m_button1;

2.View.cpp中關鍵源代碼:

int a = 0, b = 0, c = 0, d = 0, e = 0;
//矩陣高度
//在Ondraw函數中添加以下代碼:
	pDC->SetMapMode(MM_ISOTROPIC);
	pDC->SetViewportOrg(200,450);//設置原點
	pDC->MoveTo(100, 0);//從100,0畫到1300,0
	pDC->LineTo(1300, 0);

	//設置畫筆參數
	CBrush brush;
	//畫筆顏色
	brush.CreateHatchBrush(HS_BDIAGONAL, RGB(150, 100, 45));	
	pDC->SelectObject(brush);

	int i = 1;

	//繪製矩形,分別爲四個點座標
	pDC->Rectangle(200, 0, 400, 50*a);
	pDC->Rectangle(400, 0, 600, 50 * b);
	pDC->Rectangle(600, 0, 800, 50 * c);
	pDC->Rectangle(800, 0, 1000, 50 * d);
	pDC->Rectangle(1000, 0, 1200, 50 * e);

	//設置分段文本座標
	pDC->TextOut(250, 0, " <60");
	pDC->TextOut(450, 0, "60-70");
	pDC->TextOut(650, 0, "70-80");
	pDC->TextOut(850, 0, "80-90");
	pDC->TextOut(1050, 0, "90-100");
	
	//設置文字高度(多少人)
	CString y1,y2,y3,y4,y5;
	y1.Format("%d", a);
	y2.Format("%d", b);
	y3.Format("%d", c);
	y4.Format("%d", d);
	y5.Format("%d", e);

	//x軸從250-1050
	pDC->MoveTo(250, 50 * a + 100);
	pDC->LineTo(450, 50 * b + 100);
	pDC->LineTo(650, 50 * c + 100);
	pDC->LineTo(850, 50 * d + 100);
	pDC->LineTo(1050, 50 * e + 100);

	//設置文本位置
	if(a!=0)
	pDC->TextOut(250, 27 * a, y1 + "人");
	if (b != 0)
	pDC->TextOut(450, 27 * b, y2 + "人");
	if (c != 0)
	pDC->TextOut(650, 27 * c, y3 + "人");
	if (d != 0)
	pDC->TextOut(850, 27 * d, y4 + "人");
	if (e != 0)
	pDC->TextOut(1050, 27 * e, y5 + "人");
//在類嚮導中添加處理程序OnCreate
//在View.cpp中OnCreate函數添加以下代碼:
	m_button.Create("高等數學",//設置按鈕1標題
		WS_CHILD | WS_VISIBLE | WS_BORDER,

		//設置按鈕1座標
		CRect(1200, 10, 1360, 60),
		this,
		IDC_BUTTON1);
	m_button.ShowWindow(SW_SHOWNORMAL);
	
	m_button1.Create("C++",//設置按鈕2標題
		WS_CHILD | WS_VISIBLE | WS_BORDER,

		//設置按鈕2座標
		CRect(1200, 70, 1360, 120),
		this,
		IDC_BUTTON2);
	m_button1.ShowWindow(SW_SHOWNORMAL);

//兩個按鈕的函數實現
void CDrawT12View::OnClickButton1()
{
	//按鈕1實現
	
	//初始化
	a = b = c = d = e = 0;
	
	//打開文件並且操作
	CFileDialog fdlg(TRUE, ".dat", "save", OFN_OVERWRITEPROMPT, "數據文件(*.txt)|*.txt|所有文件(*.*)|*.*||", NULL);

	//如果成功讀取文件
	if (fdlg.DoModal() == IDOK)
	{
		CStdioFile file(fdlg.GetPathName(), CFile::modeRead);
		CString cs;

		int i = 0;
		while (file.ReadString(cs))
		{
			//當還能讀取到行
			if (i % 4 == 2)
			{
				//如果是高數成績,則轉換爲數值再判斷大小
				long long q = _ttoi(cs);
				if (q < 60) a++;
				else if (q >= 60 && q <= 70) b++;
				else if (q > 70 && q <= 80) c++;
				else if (q > 80 && q <= 90) d++;
				else if (q > 90) e++;
				
			}
			i++;
		}
	}
	InvalidateRect(NULL);
}

void CDrawT12View::OnClickButton2()
{
	//按鈕2實現

	//初始化
	a = b = c = d = e = 0;

	//打開文件並且操作
	CFileDialog fdlg(TRUE, ".dat", "save", OFN_OVERWRITEPROMPT, "數據文件(*.txt)|*.txt|所有文件(*.*)|*.*||", NULL);

	//如果成功讀取文件
	if (fdlg.DoModal() == IDOK)
	{
		CStdioFile file(fdlg.GetPathName(), CFile::modeRead);
		CString cs;

		int i = 0;
		while (file.ReadString(cs))
		{
			//當還能讀取到行
			if (i % 4 == 3)
			{
				//如果是C++成績,則轉換爲數值再判斷大小
				long long q = _ttoi(cs);
				if (q < 60) a++;
				else if (q >= 60 && q <= 70) b++;
				else if (q > 70 && q <= 80) c++;
				else if (q > 80 && q <= 90) d++;
				else if (q > 90) e++;
			}
			i++;
		}
	}
	InvalidateRect(NULL);
}

(4)程序運行時的效果圖:
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
在這裏插入圖片描述
(5).實驗結果分析,實驗收穫和體會:

這次mfc實驗是對話框實現以及View單文檔視圖的綜合應用

1.這次實驗進行初期,我對MFC中工具箱中控件跟實際映射的變量以及函數應用不太熟練,經過實驗,我熟悉了MFC的Dlg界面設計,以及各個控件之間的關聯綁定。

2.這次實驗需要大量使用MFC中各個控件的自帶函數(例如讀寫txt文件,list control的函數方法等等),需要在網上查找資料,經過實驗後,使得我對這些函數的使用更加的熟悉了。

3.經過實驗,我鞏固了頭文件的編寫與多cpp的編寫形式。

4.在cpp文件運用頭文件中書寫的類時會出現很多問題:無法識別頭文件中的類,將頭文件stdafx.h書寫在最前面include就解決了問題,具體原因未知。

5.試驗初期,我運用了CArray(MFC自帶的模板容器)來存儲學生類,很快就完成完了要求,但是後來因爲老師不允許使用STL容器以及其他容器,所以自己寫了一個容器,並且通過自己實現了很多類容器的函數方法,讓我更加提升了自己的代碼能力。

6.實驗要求實現MFC單文檔內展示兩個不同的直方/折現圖,因此需要在單文檔視圖中添加按鈕實現,於是我在網上查找資料學習到了在MFC單文檔中安置按鈕的方法,以及熟悉了在MFC中CBrush(畫筆)的函數方法使用。

7.實現排序功能時,我寫了多個cmp用於實現多個排序方法,再用algorithm頭文件中的sort函數進行快排,實現便捷並且效率高。
8.在實現直方圖/折線圖的時候,實現界面的標題是未定義標題,覺得有點不太好看(截圖在實驗報告不美觀),因此在網上查找資料,學會了更改標題的方法。

(6)實驗的改進意見和建議:

1.實驗要求中沒有要求到的,我覺得挺重要的按鈕:按學號查找,我的想法是在容器類中添加find函數用於查找參數中輸入的int學號,再彈出對話框顯示該學號學生的所有信息。

2.在學生管理系統中,雖然實驗沒有要求,但是我添加了反選的按鈕,因爲我發現在調試的時候,要一個個勾選刪除比較麻煩,所以添加反選按鈕實現一鍵刪除功能。

3.我認爲判斷是否學號重複添加的功能是很需要的,因此我在類容器中寫了個查找學號是否重複的函數,用於實現這個功能,若重複添加則彈出“學號重複”信息框。

總結:(之前覺得MFC是個上世紀的產物,覺得沒用,課也沒聽,但是爲了寫這課程設計,還特地去學,枯遼,但是感覺學會了還行8)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章