一、课程设计题目及内容
(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)对单文档的绘图功能有了一定的了解。