一、課程設計題目及內容
(1)設計一個學生類Student,包括數據成員:姓名、學號、二門課程(面向對象程序設計、高等數學)的成績。
(2)創建一個管理學生的類Management,包括實現學生的數據的增加、刪除、修改、按課程成績排序、保存學生數據到文件及加載文件中的數據等功能。
(3)創建一個基於對話框的MFC應用程序,程序窗口的標題上有你姓名、學號和應用程序名稱。使用(1)和(2)中的類,實現對學生信息和成績的輸入和管理。
(4)創建一個單文檔的MFC應用程序,讀取(3)中保存的文件中的學生成績,分別用直方圖和折線方式顯示所有學生某課程的成績分佈圖。
二、程序中使用的數據及主要符號說明
//管理系統數據
CString studyNumber; //學號
CString name; //姓名
CListBox lis; //列表名
afx_msg void OnBnClickedButton1();
afx_msg void OnBnClickedButton2();
afx_msg void OnBnClickedButton3();
afx_msg void OnLbnSelchangeList1();
CButton del; //刪除鍵命名
afx_msg void OnBnClickedButton4();
afx_msg void OnBnClickedButton5();
void Removelis(); //清除列表
afx_msg void OnDestroy(); //銷燬函數
CString address; //通信地址
int sorting; //排序下拉列表變量
afx_msg void OnCbnSelchangeCombo2();
afx_msg void OnBnClickedButton6();
BOOL sex; //性別
CString age; //年齡
CString mTest; //數學成績
CString cTest; //C++成績CString temp; //臨時字符串
Student* pImfo = new Student; //學生類指針
//繪圖數據
afx_msg void OnFilePrintPreview();
afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
DECLARE_MESSAGE_MAP()
void DrawScore(CDC* pDC, int * fScore, int nNum);
void Drawlist(CDC * pDC, int * fScore, int nNum);
CButton m_button1, m_button2, m_button3, m_button4, m_button5, m_button6;
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
int m_Num[1000];
afx_msg void OnHigger1();
afx_msg void OnHigger2();
afx_msg void OnHigger4();
afx_msg void OnHigger5();
三、帶有詳細註釋的自己編寫的源程序
// Students.h
#pragma once
class Student {
public:
char Name[10]; //姓名
char StudyNumber[20]; //學號
bool Sex; //性別
char Age[6]; //年齡
char CTest[6]; //C++成績(C++Test)
char MTest[6]; //數學成績(MathTest)
char Test[6]; //總成績的字符型數值
char Address[100]; //通信地址
};
// 管理系統Dlg.h
// 管理系統Dlg.h : 頭文件
#pragma once
#include "afxwin.h"
#include"Students.h"
// C管理系統Dlg 對話框
class C管理系統Dlg : public CDialogEx
{
// 構造
public:
C管理系統Dlg(CWnd* pParent = NULL); // 標準構造函數
// 對話框數據
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_MY_DIALOG };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 實現
protected:
HICON m_hIcon;
// 生成的消息映射函數
virtual BOOL OnInitDialog();
afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
afx_msg void OnPaint();
afx_msg HCURSOR OnQueryDragIcon();
DECLARE_MESSAGE_MAP()
public:
CString studyNumber; //學號
CString name; //姓名
CListBox lis; //列表名
afx_msg void OnBnClickedButton1();
afx_msg void OnBnClickedButton2();
afx_msg void OnBnClickedButton3();
afx_msg void OnLbnSelchangeList1();
CButton del; //刪除鍵命名
afx_msg void OnBnClickedButton4();
afx_msg void OnBnClickedButton5();
void Removelis(); //清除列表
afx_msg void OnDestroy(); //銷燬函數
CString address; //通信地址
int sorting; //排序下拉列表變量
afx_msg void OnCbnSelchangeCombo2();
afx_msg void OnBnClickedButton6();
BOOL sex; //性別
CString age; //年齡
CString mTest; //數學成績
CString cTest; //C++成績
};
// 管理系統Dlg.cpp
// 管理系統Dlg.cpp : 實現文件
//
#include "stdafx.h"
#include "管理系統.h"
#include "管理系統Dlg.h"
#include "afxdialogex.h"
#include <fstream>
#include <iostream>
#include <algorithm>
#include <list>
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
using namespace std;
// 用於應用程序“關於”菜單項的 CAboutDlg 對話框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 對話框數據
#ifdef AFX_DESIGN_TIME
enum { IDD = IDD_ABOUTBOX };
#endif
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 實現
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(IDD_ABOUTBOX)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// C管理系統Dlg 對話框
//初始化類變量
C管理系統Dlg::C管理系統Dlg(CWnd* pParent /*=NULL*/)
: CDialogEx(IDD_MY_DIALOG, pParent)
, studyNumber(_T(""))
, name(_T(""))
, address(_T(""))
, sorting(0)
, sex(FALSE)
, age(_T(""))
, mTest(_T(""))
, cTest(_T(""))
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void C管理系統Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Text(pDX, IDC_EDIT1, studyNumber);
DDX_Text(pDX, IDC_EDIT2, name);
// DDX_Radio(pDX, IDC_RADIO1, sex);
// DDX_Text(pDX, IDC_EDIT3, age);
// DDX_Text(pDX, IDC_EDIT5, mTest);
// DDX_Text(pDX, IDC_EDIT6, cTest);
DDX_Control(pDX, IDC_LIST1, lis);
DDX_Control(pDX, IDC_BUTTON2, del);
DDX_Text(pDX, IDC_EDIT7, address);
DDX_CBIndex(pDX, IDC_COMBO2, sorting);
DDX_Radio(pDX, IDC_RADIO1, sex);
DDX_Text(pDX, IDC_EDIT3, age);
DDX_Text(pDX, IDC_EDIT5, mTest);
DDV_MaxChars(pDX, mTest, 10);
DDX_Text(pDX, IDC_EDIT6, cTest);
DDV_MaxChars(pDX, cTest, 10);
}
BEGIN_MESSAGE_MAP(C管理系統Dlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, &C管理系統Dlg::OnBnClickedButton1)
ON_BN_CLICKED(IDC_BUTTON2, &C管理系統Dlg::OnBnClickedButton2)
ON_BN_CLICKED(IDC_BUTTON3, &C管理系統Dlg::OnBnClickedButton3)
ON_LBN_SELCHANGE(IDC_LIST1, &C管理系統Dlg::OnLbnSelchangeList1)
ON_BN_CLICKED(IDC_BUTTON4, &C管理系統Dlg::OnBnClickedButton4)
ON_BN_CLICKED(IDC_BUTTON5, &C管理系統Dlg::OnBnClickedButton5)
ON_WM_DESTROY()
ON_CBN_SELCHANGE(IDC_COMBO2, &C管理系統Dlg::OnCbnSelchangeCombo2)
ON_BN_CLICKED(IDC_BUTTON6, &C管理系統Dlg::OnBnClickedButton6)
END_MESSAGE_MAP()
// C管理系統Dlg 消息處理程序
BOOL C管理系統Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 將“關於...”菜單項添加到系統菜單中。
// IDM_ABOUTBOX 必須在系統命令範圍內。
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 設置此對話框的圖標。 當應用程序主窗口不是對話框時,框架將自動
// 執行此操作
SetIcon(m_hIcon, TRUE); // 設置大圖標
SetIcon(m_hIcon, FALSE); // 設置小圖標
// TODO: 在此添加額外的初始化代碼
return TRUE; // 除非將焦點設置到控件,否則返回 TRUE
}
void C管理系統Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向對話框添加最小化按鈕,則需要下面的代碼
// 來繪製該圖標。 對於使用文檔/視圖模型的 MFC 應用程序,
// 這將由框架自動完成。
void C管理系統Dlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用於繪製的設備上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);
// 使圖標在工作區矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 繪製圖標
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
}
//當用戶拖動最小化窗口時系統調用此函數取得光標
//顯示。
HCURSOR C管理系統Dlg::OnQueryDragIcon()
{
return static_cast<HCURSOR>(m_hIcon);
}
void C管理系統Dlg::OnBnClickedButton1()
{
// 增加
if (UpdateData(true))
{
CString temp; //臨時字符串
Student* pImfo = new Student; //學生類指針,用於存儲當前畫面新填入的信息
//將畫面中的信息存儲到指針指向的類中
strcpy_s(pImfo->Name, name);
strcpy_s(pImfo->StudyNumber, studyNumber);
strcpy_s(pImfo->Address, address);
pImfo->Sex = sex;
strcpy_s(pImfo->Age, age);
strcpy_s(pImfo->MTest, mTest);
strcpy_s(pImfo->CTest, cTest);
int e = _ttoi(_T(mTest));
int f = _ttoi(_T(cTest));
temp.Format(_T("%d"), (e+f));
strcpy_s(pImfo->Test, temp);
//添加列表項目
CString LongName = pImfo->Name; //字符串LongName用於添加列表名稱
LongName.Append(" 總分");
LongName.Append(pImfo->Test);
int nIndex = lis.AddString(LongName); //接收索引號
lis.SetItemData(nIndex, (DWORD_PTR)pImfo); //設置相應項目ID
//清空畫面操作
name = "";
studyNumber = "";
address = "";
sex = 0;
age = "";
mTest = "";
cTest = "";
UpdateData(FALSE);
}
}
void C管理系統Dlg::OnBnClickedButton2()
{
// 刪除
int nCur = lis.GetCurSel(); //讀取當前點中的列表索引號
if (nCur != LB_ERR)
{
Student* pImfo = (Student*)lis.GetItemData(nCur); //類指針指向對應列表數據
lis.DeleteString(nCur); //刪除該列
//清空數據
name = "";
studyNumber = "";
address = "";
sex = 0;
age = "";
mTest = "";
cTest = "";
// 判斷當前行數,若行數爲0,則刪除鍵不可見
if (lis.GetCount() == 0)
{
del.EnableWindow(FALSE);
}
UpdateData(FALSE);
delete pImfo; //釋放指針防止內存泄漏
}
}
void C管理系統Dlg::OnBnClickedButton3()
{
// 修改
// 思路:刪舊增新
int nCur = lis.GetCurSel(); //讀取當前點中的列表索引號
if (nCur != LB_ERR)
{
Student* pImfo = (Student*)lis.GetItemData(nCur); //類指針指向對應列表數據
lis.DeleteString(nCur); //刪除該列
delete pImfo; //釋放指針防止內存泄漏
}
OnBnClickedButton1(); //調用“增加”按鈕,讀取當前畫面中的信息將其再次添加
}
void C管理系統Dlg::OnLbnSelchangeList1()
{
// 列表事件
int nCur = lis.GetCurSel(); //讀取當前點中的列表索引號
if (nCur != LB_ERR)
{
del.EnableWindow(TRUE); //if (nCur != LB_ERR)→有選中列表→可以刪除→刪除鍵可見
Student* pImfo = (Student*)lis.GetItemData(nCur); //類指針指向對應列表數據
//數據讀取
name = pImfo->Name;
address = pImfo->Address;
studyNumber = pImfo->StudyNumber;
sex = pImfo->Sex;
age = pImfo->Age;
mTest = pImfo->MTest;
cTest = pImfo->CTest;
UpdateData(FALSE);
}
}
void C管理系統Dlg::OnBnClickedButton4()
{
// TODO: 保存
CFileDialog dlg(FALSE); //打開“另存爲”界面
if (dlg.DoModal() == IDOK)
{
CString strFile = dlg.GetPathName(); //返回文件路徑
ofstream out(strFile, ios::binary); //二進制寫入數據
if (out.is_open())
{
int n = lis.GetCount(); //獲取當前信息數目
//將信息寫入文件中
out.write((char*)&n, sizeof(int));
for (int i = 0; i < n; i++)
{
Student* pImfo = (Student*)lis.GetItemData(i);
out.write((char*)pImfo, sizeof(Student));
}
}
}
}
void C管理系統Dlg::OnBnClickedButton5()
{
// TODO: 讀取
CFileDialog dlg(TRUE); //打開“打開”界面
if (dlg.DoModal() == IDOK)
{
Removelis(); //清空當前列表
CString strFile = dlg.GetPathName(); //返回文件路徑
ifstream in(strFile, ios::binary); //二進制讀出數據
if (in.is_open())
{
int n = lis.GetCount(); //獲取當前信息數目
//從文件中讀取信息
in.read((char*)&n, sizeof(int));
for (int i = 0; i < n; i++)
{
Student* pImfo = new Student;
in.read((char*)pImfo, sizeof(Student));
CString LongName = pImfo->Name; //字符串LongName用於添加列表名稱
LongName.Append(" 總分");
LongName.Append(pImfo->Test);
int nIndex = lis.AddString(LongName); //接收索引號
lis.SetItemData(nIndex, (DWORD_PTR)pImfo); //設置相應項目ID
}
OnLbnSelchangeList1(); //更新列表欄
}
else
{
AfxMessageBox("Open File Err");
}
}
}
//快排調用
BOOL cmpAll(Student* pt1, Student* pt2) //比較總成績
{
int temp1 = _ttoi(_T(pt1->Test));
int temp2 = _ttoi(_T(pt2->Test));
return temp1 > temp2;
}
BOOL cmpM(Student* pt1, Student* pt2) //比較數學成績
{
int temp1 = _ttoi(_T(pt1->MTest));
int temp2 = _ttoi(_T(pt2->MTest));
return temp1 > temp2;
}
BOOL cmpC(Student* pt1, Student* pt2) //比較C成績
{
int temp1 = _ttoi(_T(pt1->CTest));
int temp2 = _ttoi(_T(pt2->CTest));
return temp1 > temp2;
}
void C管理系統Dlg::Removelis()
{
//列表清除
int n = lis.GetCount(); //獲取當前信息數目
//逐條讀取指針,釋放指針
for (int i = 0; i < n; i++)
{
Student* pImfo = (Student*)lis.GetItemData(i);
delete pImfo;
}
lis.ResetContent(); //釋放內容
OnLbnSelchangeList1(); //更新列表欄
}
void C管理系統Dlg::OnDestroy()
{
CDialogEx::OnDestroy();
Removelis(); //在關閉整個頁面前正確釋放指針,避免內存泄漏
// TODO: 在此處添加消息處理程序代碼
}
void C管理系統Dlg::OnCbnSelchangeCombo2()
{
// 排序
if (UpdateData(true)) {
//使用容器讀取信息,進行排序
list<Student*> sts;
int num = lis.GetCount();
Student *temp;
for (int i = 0; i < lis.GetCount(); i++)
{
temp = (Student*)lis.GetItemData(i);
sts.push_back(temp);
}
//根據下拉列表框的選擇執行不同的排序
switch (sorting)
{
case 0:
break;
case 1:
sts.sort(cmpM); //按照數學成績排序
break;
case 2:
sts.sort(cmpC); //按照程序設計成績排序
break;
case 3:
sts.sort(cmpAll); //按照總成績排序
break;
}
//逐條刪除列表
while (lis.GetCount() > 0) lis.DeleteString(0);
//將在容器中排好序的信息再添加到列表中
for (auto iter = sts.begin(); iter != sts.end(); ++iter)
{
auto st = *iter;
CString LongName = st->Name; //字符串LongName用於添加列表名稱
LongName.Append(" 總分");
LongName.Append(st->Test);
lis.AddString(LongName);
lis.SetItemDataPtr(lis.GetCount() - 1, st);
}
}
}
void C管理系統Dlg::OnBnClickedButton6()
{
// 呼叫繪圖程序
ShellExecute(NULL, "open", ".\\MFCApplication8.exe", NULL, NULL, SW_SHOWNORMAL);
}
// MFCApplication8View.h
// MFCApplication8View.h : CMFCApplication8View 類的接口
//
#pragma once
class CMFCApplication8View : public CView
{
protected: // 僅從序列化創建
CMFCApplication8View();
DECLARE_DYNCREATE(CMFCApplication8View)
// 特性
public:
CMFCApplication8Doc* GetDocument() const;
// 操作
public:
// 重寫
public:
virtual void OnDraw(CDC* pDC); // 重寫以繪製該視圖
virtual BOOL PreCreateWindow(CREATESTRUCT& cs);
protected:
virtual BOOL OnPreparePrinting(CPrintInfo* pInfo);
virtual void OnBeginPrinting(CDC* pDC, CPrintInfo* pInfo);
virtual void OnEndPrinting(CDC* pDC, CPrintInfo* pInfo);
// 實現
public:
virtual ~CMFCApplication8View();
#ifdef _DEBUG
virtual void AssertValid() const;
virtual void Dump(CDumpContext& dc) const;
#endif
protected:
// 生成的消息映射函數
protected:
afx_msg void OnFilePrintPreview();
afx_msg void OnRButtonUp(UINT nFlags, CPoint point);
afx_msg void OnContextMenu(CWnd* pWnd, CPoint point);
DECLARE_MESSAGE_MAP()
void DrawScore(CDC* pDC, int * fScore, int nNum);
void Drawlist(CDC * pDC, int * fScore, int nNum);
CButton m_button1, m_button2, m_button3, m_button4, m_button5, m_button6;
public:
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
int m_Num[1000];
afx_msg void OnHigger1();
afx_msg void OnHigger2();
afx_msg void OnHigger4();
afx_msg void OnHigger5();
};
#ifndef _DEBUG // MFCApplication8View.cpp 中的調試版本
inline CMFCApplication8Doc* CMFCApplication8View::GetDocument() const
{ return reinterpret_cast<CMFCApplication8Doc*>(m_pDocument); }
#endif
// MFCApplication8View.cpp
// MFCApplication8View.cpp : CMFCApplication8View 類的實現
//
#include "stdafx.h"
// SHARED_HANDLERS 可以在實現預覽、縮略圖和搜索篩選器句柄的
// ATL 項目中進行定義,並允許與該項目共享文檔代碼。
#ifndef SHARED_HANDLERS
#include "MFCApplication8.h"
#endif
#include "MFCApplication8Doc.h"
#include "MFCApplication8View.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
#include <fstream>
#include "Students.h"
using namespace std;
// CMFCApplication8View
IMPLEMENT_DYNCREATE(CMFCApplication8View, CView)
BEGIN_MESSAGE_MAP(CMFCApplication8View, CView)
// 標準打印命令
ON_COMMAND(ID_FILE_PRINT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_DIRECT, &CView::OnFilePrint)
ON_COMMAND(ID_FILE_PRINT_PREVIEW, &CMFCApplication8View::OnFilePrintPreview)
ON_WM_CONTEXTMENU()
ON_WM_RBUTTONUP()
ON_WM_CREATE()
ON_COMMAND(IDC_HIGGER1, &CMFCApplication8View::OnHigger1)
ON_COMMAND(IDC_HIGGER2, &CMFCApplication8View::OnHigger2)
ON_COMMAND(IDC_HIGGER4, &CMFCApplication8View::OnHigger4)
ON_COMMAND(IDC_HIGGER5, &CMFCApplication8View::OnHigger5)
END_MESSAGE_MAP()
// CMFCApplication8View 構造/析構
CMFCApplication8View::CMFCApplication8View()
{
// TODO: 在此處添加構造代碼
}
CMFCApplication8View::~CMFCApplication8View()
{
}
BOOL CMFCApplication8View::PreCreateWindow(CREATESTRUCT& cs)
{
// TODO: 在此處通過修改
// CREATESTRUCT cs 來修改窗口類或樣式
return CView::PreCreateWindow(cs);
}
// CMFCApplication8View 繪製
void CMFCApplication8View::OnDraw(CDC* pDC)
{
CMFCApplication8Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
}
void CMFCApplication8View::OnFilePrintPreview()
{
#ifndef SHARED_HANDLERS
AFXPrintPreview(this);
#endif
}
BOOL CMFCApplication8View::OnPreparePrinting(CPrintInfo* pInfo)
{
// 默認準備
return DoPreparePrinting(pInfo);
}
void CMFCApplication8View::OnRButtonUp(UINT /* nFlags */, CPoint point)
{
ClientToScreen(&point);
OnContextMenu(this, point);
}
void CMFCApplication8View::OnContextMenu(CWnd* /* pWnd */, CPoint point)
{
#ifndef SHARED_HANDLERS
theApp.GetContextMenuManager()->ShowPopupMenu(IDR_POPUP_EDIT, point.x, point.y, this, TRUE);
#endif
}
// CMFCApplication8View 診斷
#ifdef _DEBUG
void CMFCApplication8View::AssertValid() const
{
CView::AssertValid();
}
void CMFCApplication8View::Dump(CDumpContext& dc) const
{
CView::Dump(dc);
}
CMFCApplication8Doc* CMFCApplication8View::GetDocument() const // 非調試版本是內聯的
{
ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CMFCApplication8Doc)));
return (CMFCApplication8Doc*)m_pDocument;
}
#endif //_DEBUG
// CMFCApplication8View 消息處理程序
void CMFCApplication8View::DrawScore(CDC* pDC, int * fScore, int nNum) //畫直方圖函數
{
// fScore是成績數組指針,nNum是學生人數
int nScoreNum[] = { 0, 0, 0, 0, 0 }; // 各成績段的人數的初 始值
// 下面是用來統計各分數段的人數
for (int i = 0; i < nNum; i++)
{
int nSeg = (int)(fScore[i]) / 10; // 取數的"十"位上的值
if (nSeg < 6) nSeg = 5; // <60分
if (nSeg == 10) nSeg = 9;// 當爲100分,算爲>90分數段
nScoreNum[nSeg - 5] ++; // 各分數段計數
}
int nSegNum = sizeof(nScoreNum) / sizeof(int); // 計算有多少個分數段
// 求分數段上最大的人數
int nNumMax = nScoreNum[0];
for (int i = 1; i < nSegNum; i++)
{
if (nNumMax < nScoreNum[i])
nNumMax = nScoreNum[i];
}
CRect rc;
GetClientRect(rc);
rc.DeflateRect(280, 40); // 縮小矩形大小
int nSegWidth = rc.Width() / nSegNum; // 計算每段的寬度
int nSegHeight = rc.Height() / nNumMax; // 計算每段的單位高度
COLORREF crSeg = RGB(0, 0, 192); // 定義一個顏色變量
CBrush brush1(HS_FDIAGONAL, crSeg);
CBrush brush2(HS_BDIAGONAL, crSeg);
CPen pen(PS_INSIDEFRAME, 2, crSeg);
CBrush* oldBrush = pDC->SelectObject(&brush1); // 將brush1選入設備環境
CPen* oldPen = pDC->SelectObject(&pen); // 將pen選 入設備環境
CRect rcSeg(rc);
rcSeg.right = rcSeg.left + nSegWidth; // 使每段的矩形寬度等於nSegWidth
CString strSeg[] = { (CString)"<60", (CString)"60-70", (CString)"70-80", (CString)"80-90", (CString)">=90" };
CRect rcStr;
for (int i = 0; i<nSegNum; i++)
{ // 保證相鄰的矩形填充樣式不相同
if (i % 2)
pDC->SelectObject(&brush2);
else
pDC->SelectObject(&brush1);
rcSeg.top = rcSeg.bottom - nScoreNum[i] * nSegHeight - 2; // 計算每段矩形的高度
pDC->Rectangle(rcSeg);
if (nScoreNum[i] > 0)
{
CString str;
str.Format((CString)"%d人", nScoreNum[i]);
pDC->DrawText(str, rcSeg, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
}
rcStr = rcSeg;
rcStr.top = rcStr.bottom + 2;
rcStr.bottom += 20;
pDC->DrawText(strSeg[i], rcStr, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
rcSeg.OffsetRect(nSegWidth, 0); // 右移矩形
}
pDC->SelectObject(oldBrush); // 恢復原來的畫刷屬性
pDC->SelectObject(oldPen); // 恢復原來的畫筆屬性
CDC* pControlDC = pDC;
pControlDC->SelectStockObject(BLACK_BRUSH);//設置畫刷
CString str;
}
void CMFCApplication8View::Drawlist(CDC* pDC, int* fScore, int nNum)//畫折線圖
{
// fScore是成績數組指針,nNum是學生人數
int nScoreNum[] = { 0, 0, 0, 0, 0 }; // 各成績段的人數的初 始值
// 下面是用來統計各分數段的人數
for (int i = 0; i < nNum; i++)
{
int nSeg = (int)(fScore[i]) / 10; // 取數的"十"位上的值
if (nSeg < 6) nSeg = 5; // <60分
if (nSeg == 10) nSeg = 9;// 當爲100分,算爲>90分數段
nScoreNum[nSeg - 5] ++; // 各分數段計數
}
CDC* pControlDC = pDC;
pControlDC->SelectStockObject(BLACK_BRUSH);//設置畫刷
CString str;
CString strSeg[] = { (CString)"<60", (CString)"60-70", (CString)"70-80", (CString)"80-90", (CString)">=90" };
pControlDC->MoveTo(280, 40);//畫線的開始位置
pControlDC->LineTo(280, 380);
pControlDC->MoveTo(280, 380);//畫線的開始位置
pControlDC->LineTo(900, 380);
pControlDC->MoveTo(280, 380);
for (int i = 0; i < 5; i++)
{
pControlDC->SetPixel(0, 290, RGB(0, 0, 255)); //設置點的位置及顏色
pControlDC->LineTo(i * 140 + 280, 380 - (380 * nScoreNum[i] / nNum));//換兩點之間的線
str.Format("%d人", nScoreNum[i]);
pControlDC->TextOut(i * 140 + 280, 380 - (380 * nScoreNum[i] / nNum) - 20, str);//在線的上方輸出文字
pControlDC->TextOut(i * 140 + 280, 390, strSeg[i]);
}
}
int CMFCApplication8View::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
m_button1.Create((CString)"數學(直方)",//按鈕標題
WS_CHILD | WS_VISIBLE | WS_BORDER,//按鈕風格
CRect(10, 10, 200, 40), //按鈕大小
this, //按鈕父指針
IDC_HIGGER1); //該按鈕對應的ID號
m_button1.ShowWindow(SW_SHOWNORMAL);
m_button2.Create((CString)"程序設計(直方)",//按鈕標題
WS_CHILD | WS_VISIBLE | WS_BORDER,//按鈕風格
CRect(10, 60, 200, 90), //按鈕大小
this, //按鈕父指針
IDC_HIGGER2); //該按鈕對應的ID號
m_button2.ShowWindow(SW_SHOWNORMAL);
m_button4.Create((CString)"(折線)",//按鈕標題
WS_CHILD | WS_VISIBLE | WS_BORDER,//按鈕風格
CRect(200, 10, 270, 40), //按鈕大小
this, //按鈕父指針
IDC_HIGGER4); //該按鈕對應的ID號
m_button4.ShowWindow(SW_SHOWNORMAL);
m_button5.Create((CString)"(折線)",//按鈕標題
WS_CHILD | WS_VISIBLE | WS_BORDER,//按鈕風格
CRect(200, 60, 270, 90), //按鈕大小
this, //按鈕父指針
IDC_HIGGER5); //該按鈕對應的ID號
m_button5.ShowWindow(SW_SHOWNORMAL);
return 0;
}
void CMFCApplication8View::OnHigger1()
{
// TODO: 在此添加命令處理程序代碼
CFileDialog dlg(TRUE); //打開“打開”界面
if (dlg.DoModal() == IDOK)
{
CString strFile = dlg.GetPathName(); //返回文件路徑
CFile file;
if (!file.Open(strFile, CFile::modeReadWrite | CFile::shareDenyNone))
{
AfxMessageBox("文件無法打開,無法畫圖!");
return;
}
Student u;
int i = 0;
int n;
file.Read((char*)&n, sizeof(int));
while (file.Read(&u, sizeof(u)) == sizeof(u))
{
m_Num[i] = _ttoi((CString)u.MTest);
i++;
}
InvalidateRect(NULL);
UpdateWindow();
DrawScore(GetDC(), m_Num, i);
file.Close();
}
}
void CMFCApplication8View::OnHigger2()
{
// TODO: 在此添加命令處理程序代碼
CFileDialog dlg(TRUE); //打開“打開”界面
if (dlg.DoModal() == IDOK)
{
CString strFile = dlg.GetPathName(); //返回文件路徑
CFile file;
if (!file.Open(strFile, CFile::modeReadWrite | CFile::shareDenyNone))
{
AfxMessageBox("文件無法打開,無法畫圖!");
return;
}
Student u;
int i = 0;
int n;
file.Read((char*)&n, sizeof(int));
while (file.Read(&u, sizeof(u)) == sizeof(u))
{
m_Num[i] = _ttoi((CString)u.CTest);
i++;
}
InvalidateRect(NULL);
UpdateWindow();
DrawScore(GetDC(), m_Num, i);
file.Close();
}
}
void CMFCApplication8View::OnHigger4()
{
// TODO: 在此添加命令處理程序代碼
CFileDialog dlg(TRUE); //打開“打開”界面
if (dlg.DoModal() == IDOK)
{
CString strFile = dlg.GetPathName(); //返回文件路徑
CFile file;
if (!file.Open(strFile, CFile::modeReadWrite | CFile::shareDenyNone))
{
AfxMessageBox("文件無法打開,無法畫圖!");
return;
}
Student u;
int i = 0;
int n;
file.Read((char*)&n, sizeof(int));
while (file.Read(&u, sizeof(u)) == sizeof(u))
{
m_Num[i] = _ttoi((CString)u.MTest);
i++;
}
InvalidateRect(NULL);
UpdateWindow();
Drawlist(GetDC(), m_Num, i);
file.Close();
}
}
void CMFCApplication8View::OnHigger5()
{
// TODO: 在此添加命令處理程序代碼
CFileDialog dlg(TRUE); //打開“打開”界面
if (dlg.DoModal() == IDOK)
{
CString strFile = dlg.GetPathName(); //返回文件路徑
CFile file;
if (!file.Open(strFile, CFile::modeReadWrite | CFile::shareDenyNone))
{
AfxMessageBox("文件無法打開,無法畫圖!");
return;
}
Student u;
int i = 0;
int n;
file.Read((char*)&n, sizeof(int));
while (file.Read(&u, sizeof(u)) == sizeof(u))
{
m_Num[i] = _tstoi(u.CTest);
i++;
}
InvalidateRect(NULL);
UpdateWindow();
Drawlist(GetDC(), m_Num, i);
file.Close();
}
}
// Resource.h
//四個繪圖按鈕
#define IDC_HIGGER1 5001
#define IDC_HIGGER2 5002
#define IDC_HIGGER4 5004
#define IDC_HIGGER5 5005
四、程序運行時的效果圖
-
初始界面
-
填寫信息
-
點選“增加”後
-
點選左側列表框對信息進行修改
-
點擊修改後可見左側列表框的總分和信息發生了改變
-
增加了十個項目框
-
列表框內信息:
-
點選“保存”後
-
點選“刪除”後
-
點選“讀取”後
-
“打開”文件後
-
排序方式選擇按數學成績排序後
-
列表框內信息:可見與圖中排列方式一致
-
排序方式選擇按程序設計成績排序後
-
列表框內信息:可見與圖中排列方式一致
-
排序方式選擇按總成績排序後
-
列表框內信息:可見與圖中排列方式一致
-
點選“繪圖”後
-
點選“數學(直方)”後
-
點選“數學(折線)”後
-
點選“程序設計(直方)”後
-
點選“程序設計(折線)”後
五、實驗結果分析,實驗收穫和體會。
1、實驗結果分析:
(1)調用sort函數進行排序,編寫了三種不同排序的bool型比較函數,將比較函數當陳參數傳入sort函數內。
(2)本實驗中按照降序進行排序。與一般的冒泡之類的排序方法不同的是,sort函數是通過不斷二分插入的方法進行排序的,時間複雜度爲nlogn,大大節省了排序時間。
(3)排序時將指針指向的列表內數據放入list中,然後將指針撤銷,將list內部的學生類數據按照選擇的排序方式進行排序,然後添加到列表中,實現排序。
(4)新建了Students.h頭文件存儲學生類
(5)將單文檔與管理系統關聯起來,使得在管理系統界面能夠實現繪圖功能。
(6)繪製了單文檔的按鈕,以及增加相應命令。
2、實驗收穫和體會:
(1)熟練使用UpdateDate函數進行界面數據更改與讀入。
(2)對如listbox等控件的使用有了深層次的理解
(3)對listbox的各項函數、、sort函數等的使用的更加得心應手。
(4)領悟了char與CString在調用時的區別,以及掌握了將浮點型轉化爲字符型的方法。
(5)能夠更加熟練的運用文件輸入輸出流對數據進行輸入輸出。
(6)踩過CString和double型數據的坑,後來把這些數據內容都改成了固定長度的char型。double類型和其他類型是不能緊挨着存儲的,都是會有空間浪費掉,但是作爲一個結構體存儲的時候,它們的數據會被挨在一起存放,重新讀取的時候就會出問題。
(7)對單文檔的繪圖功能有了一定的瞭解。