C++实现学生信息管理系统[界面+数据处理]
1.简单的问题描述
1.自行设计学生信息管理系统
2.实现学生信息录入、删除、查找以及浏览的功能[这个需求真的是恶心]
3.使用EasyX图形库,实现界面
4.参考视频:https://www.bilibili.com/video/av13231926
2.遇到的相关问题
2.1 重复包含
备注:
添加较为完整的问题描述
2.2 在Unicode字符集下面声明并初始化LPCTSTR类型的数组
LPCTSTR s[5] = { L"学号",L"姓名",L"英语",L"数学",L"语文" };
备注:LP【指针】、C【const】、W【wide宽字符】、T【表示在Win32环境中, 有一个_T宏】
参考链接:1、LPCTSTR LPCWSTR LPCSTR 含义
2、LPTSTR、LPCSTR、LPCTSTR、LPSTR的来源及意义 VS2005 中error C2440: 如无法从“const char [N]”转换为“LPCWSTR” 的一点总结[外网]
2.3 LPTSTR的初始化
LPTSTR temp=new TCHAR[10];
看一下 LPTSTR 的定义便可知应该怎么初始化,如下:
#ifdef _UNICODE
typedef wchar_t TCHAR;
#else
typedef char TCHAR;
#endif // _UNICODE
typedef const TCHAR* LPCTSTR;
typedef TCHAR* LPTSTR
事实上TCHAR就是宽字符类型,而LPTSTR则是宽字符类型的指针,初始化的时候只有两种方式,new TCHAR,或者是new TCHAR[SIZE],类比的如下
char* a=new char;
char* b=new char[100]
//标准规定,char占8位,也就是一个字节
2.4 CString转换为LPTSTR,CString字符串的连接,其他类型转换为CString
CString str;
//int to CString
int a=1;
str.Format(_T("%d"), a);
//float to CString
float b=1.2;
str.Format(_T("%f"), b);
//char* to CString
char* name="Liming";
str=name;
//CSting to LPTSTR
LPTSTR out_str;
out_str=str.GetBuffer();
//CString字符串的连接
CString str1;
CString str2;
str2+=str1;
2.5 函数中传入了const类型的参数,却要返回没有const的数据,需要结束const并返回
//Studet是个学生类,有一个name属性
//将Student对象存储在vector之中
//定义search方法,返回找到对应数据时指向该数据的指针
Student* search(const vector<Student>& v, const char* name) {
int count = 0;
for (auto it : v) {
if (!strcmp(it.name,name)){
return const_cast<Student*>(&v[count]);
}
count++;
}
return NULL;
}
//下面语句解除const使得该指针能够返回
//复制代码的时候不要都复制,只复制上面函数部分即可
return const_cast<Student*>(&v[count]);
2.6 有一个指向数组或者向量某元素的指针,判断这个元素是第几个
vector<int> v;//生命一个向量,需要初始化,但这里没有
int* a=&v[3];//指针指向第四个元素
int rank=a-&v[0];//得到该元素的秩
v.erase(v.begin()+(a-&v[0]));//释放该元素
2.7 debug_heap.cpp、line904、_crtisvalidheappointer不知道是什么原因的错误
//debug_heap.cpp line904 _crtisvalidheappointer
LPTSTR temp = new TCHAR[10];
InputBox(temp, 10, L"请输入学生姓名:");
outtextxy(183, 86, temp);
USES_CONVERSION;
char* c_temp=new char[20];
c_temp = T2A(temp);
stu.name = new char[strlen(c_temp) + 1];
strcpy_s(stu.name, strlen(c_temp) + 1, c_temp);
delete[] c_temp;//这里会出错,不知道是什么原因
//推测是,重复delete了同一块内存空间
3.源代码
地址:原工程文件,也可以拷贝下面的源码,自己新建工程。
文件1:School.h
#ifndef SCHOOL_H_
#define SCHOOL_H_
#include <iostream>
#include <vector>
#include <graphics.h>
#include <mmstream.h>//包含多媒体设备接口的头文件
#pragma comment(lib,"winmm.lib")//包含多媒体设备接口的库文件
#include "Student.h"
using namespace std;
const int win_width = 600;
const int win_hight = 400;
IMAGE bkimg, butimg;
//管理系统界面的初始化
void iniInterface();
//初始化:管理系统声音
void iniSound();
//初始化:管理系统文字
void iniText();
//整体初始化
void beginItf();
//插入数据
void insertIfo(vector<Student>& v);
//检测鼠标相关事件
void butPress(vector<Student>& v);
//搜索数据
void searchIfo(const vector<Student>& v);
//浏览数据
void scanIfo(const vector<Student>& v);
//删除数据
void deleteIfo(vector<Student>& v);
//重载两个查找函数
//可以使用学号或者是姓名查找
Student* search(const vector<Student>& v, const int id);
Student* search(const vector<Student>& v, const char* name);
//重载了EasyX中的文字输出函数
void outtextxy(int x, int y, Student s);
#endif // !SCHOOL_H_
文件2:Student.h
#pragma once
#include<iostream>
class Student {
public:
int id;
char *name;
float s_english;
float s_math;
float s_chinese;
};
//之所以使用char*,是为了方便后面的类型转换
文件3:School.cpp
#include "School.h"
#include <atlconv.h>
#include <atlstr.h>
#include <cstring>
int main()
{
//数据存储位置
vector<Student> stu_vct;//使用向量来存储学生数据
//vector<Student>* stu_p = &stu_vct;//声明指针指向存储学生数据的向量,以节省空间
Student s1={1111,(char*)"张三",123,123,123};
Student s2={2222,(char*)"李四",123,123,123 };
stu_vct.push_back(s1);
stu_vct.push_back(s2);
//初始化
initgraph(win_width, win_hight);
beginItf();
butPress(stu_vct);
//函数尾部,卡屏,关闭图片流
std::cin.get();
closegraph();
cout << stu_vct[0].id << endl;
std::cout << "Hello World!\n";
}
//检测鼠标相关事件
void butPress(vector<Student>& v) {
MOUSEMSG msg{};
while (true) {
msg = GetMouseMsg();
switch (msg.uMsg) {
case WM_LBUTTONDOWN://鼠标左键按下
if (msg.x > 200 && msg.x < 400 && msg.y>80 && msg.y < 130) {
//录入信息
insertIfo(v);
beginItf();
}
if (msg.x > 200 && msg.x < 400 && msg.y>140 && msg.y < 190) {
//查找信息
searchIfo(v);
beginItf();
}
if (msg.x > 200 && msg.x < 400 && msg.y>200 && msg.y < 250) {
//删除信息
deleteIfo(v);
beginItf();
}
if (msg.x > 200 && msg.x < 400 && msg.y>260 && msg.y < 310) {
//浏览信息
scanIfo(v);
beginItf();
}
break;
case WM_MOUSEMOVE://鼠标移动
if (msg.mkLButton) {
//移动过程中点击鼠标左键要做的事情
//...
}
break;
default:
break;
}
}
}
//插入一条学生信息
void insertIfo(vector<Student>& v) {
//功能完善:
// 1.不能重复插入,如果已经存在该学生信息,需要给出提示
// 2.检测对于不正当的输入,直到用户输入正确内容后停止
// 3.支持直接返回,按back键等,可以直接返回
// 4.支持文件写入,如果能够插入,则需要将该内容写入文件
Student stu;
putimage(0, 0, &bkimg);//使得背景不发生变化
//char s[][5]={ "学号","姓名","英语","数学","语文" };
//TCHAR* s[5] = { L"学号","姓名","英语","数学","语文" };
LPCTSTR s[5] = { L"学号",L"姓名",L"英语",L"数学",L"语文" };
for (int i = 0; i < 5; i++) {
setlinecolor(RED);
rectangle(100, 50 + i * 35, 500, 85 + i * 35);
outtextxy(100, 51 + i * 35, s[i]);
}
line(180, 50, 180, 225);
//LPSTR:32bit指针指向一个字符串,每个字符占1字节,等价与char
LPTSTR temp=new TCHAR[10];
InputBox(temp, 10, L"请输入学生id:");
outtextxy(183, 51, temp);
stu.id = _wtoi(temp);
InputBox(temp, 10, L"请输入学生姓名:");
outtextxy(183, 86, temp);
USES_CONVERSION;
char* c_temp;
c_temp= T2A(temp);
stu.name = new char[strlen(c_temp) + 1];
strcpy_s(stu.name,strlen(c_temp)+1, c_temp);
InputBox(temp, 10, L"请输入英语成绩:");
outtextxy(183, 121, temp);
stu.s_english = _wtof(temp);
InputBox(temp, 10, L"请输入数学成绩:");
outtextxy(183, 156, temp);
stu.s_math = _wtof(temp);
InputBox(temp, 10, L"请输入数学成绩:");
outtextxy(183, 191, temp);
stu.s_chinese = _wtof(temp);
delete[] temp;//应该清除的是temp而不是上面的c_temp
v.push_back(stu);
}
//搜索一条学生信息
void searchIfo(const vector<Student>& v) {
//支持查找id或者姓名
//下面关于界面的两条语句应该封装成一个
putimage(0, 0, &bkimg);//使得背景不发生变化
settextcolor(RGB(93, 107, 153));//调整文字颜色
settextstyle(15, 0, L"楷体");
LPTSTR temp = new TCHAR[10];
InputBox(temp, 10, L"请输入学生id或学生姓名:");
int t_id;
char* t_name;
Student* s;
if (t_id= _wtoi(temp)) {
//可以使用find_if
s=search(v, t_id);
if (s != NULL) {
outtextxy(0, 0, *s);
outtextxy(0, 16, L"请按任意键返回...");
cin.get();
}
else {
outtextxy(0, 0, L"没有该学生,请按任意键返回...");
cin.get();
}
}
else {
USES_CONVERSION;
t_name = W2A(temp);
s = search(v, t_name);
if (s != NULL) {
outtextxy(0, 0, *s);
outtextxy(0, 16, L"请按任意键返回...");
cin.get();
}
else {
outtextxy(0, 0, L"没有该学生,请按任意键返回...");
cin.get();
}
}
}
//删除学生信息
void deleteIfo(vector<Student>& v) {
putimage(0, 0, &bkimg);//使得背景不发生变化
settextcolor(RGB(93, 107, 153));//调整文字颜色
settextstyle(15, 0, L"楷体");
Student* s;
int t_id;
LPTSTR temp = new TCHAR[10];
InputBox(temp, 10, L"请输入学生id:");
if (t_id = _wtoi(temp)) {
//可以使用find_if
s = search(v, t_id);
if (s != NULL) {
outtextxy(0, 0, *s);
v.erase(v.begin() + (s - &v[0]));//利用指针按照元素块可加减的原理,调用erase()函数
outtextxy(0,16,L"已经成功删除,请按任意键返回...");
cin.get();
}
else {
outtextxy(0, 0, L"没有该学生,请按任意键返回...");
cin.get();
}
}
}
void scanIfo(const vector<Student>& v) {
//需要设置滚动效果,忽略掉了,是在不想写,恶心
}
//将下面几个初始化封装在了一起
void beginItf() {
iniSound();
iniInterface();
iniText();
}
//初始化:管理系统界面
void iniInterface() {
//加载图片
loadimage(&bkimg, L"./res/bkimg.jpg", 600, 400);//后两个参数为缩放比例
loadimage(&butimg, L"./res/butimg.jpg", 200, 50);//后两个参数为缩放比例
//loadimage(NULL, L"./res/bkimg.jpg", 600, 400);//直接将图片输出到控制台,但是测试的时候并没有
//贴图片--朝某流输出图片
putimage(0, 0, &bkimg);//坐标系在左上角,朝下
putimage(200, 80, &butimg);
putimage(200, 140, &butimg);
putimage(200, 200, &butimg);
putimage(200, 260, &butimg);
}
//初始化:管理系统声音
void iniSound() {
//打开并播放mp3文件
//mciSendString(L"open ./res/bkmusic.mp3 alias bgm", 0, 0, 0);//添加背景音乐
//mciSendString(L"play bgm repeat", 0, 0, 0);//播放背景音乐
//播放wav格式的文件
//PlaySound(L"./res/music.wav", NULL, SND_FILENAME | SND_LOOP | SND_ASYNC);//最后一个参数控制异步播放
}
//初始化:管理系统文字
void iniText() {
//设置文字样式
settextstyle(30, 0, L"楷体");
//设置文字颜色
settextcolor(RGB(204, 213, 240));
//设置文字模式
setbkmode(TRANSPARENT);
//指定位置输出文字
outtextxy(180, 20, L"XXX学校管理系统");
outtextxy(247, 88, L"录入信息");
outtextxy(247, 148, L"查找信息");
outtextxy(247, 208, L"删除信息");
outtextxy(247, 268, L"浏览信息");
}
Student* search(const vector<Student>& v, const int id) {
int count=0;
for (auto it : v) {
if (it.id == id) {
return const_cast<Student*>(&v[count]);
}
count++;
}
return NULL;
}
Student* search(const vector<Student>& v, const char* name) {
int count = 0;
for (auto it : v) {
if (!strcmp(it.name,name)){
return const_cast<Student*>(&v[count]);
}
count++;
}
return NULL;
}
void outtextxy(int x, int y, Student s) {
//连接成整个字符串,统一输出
LPTSTR out_LPT;
CString str;
CString out_str;
str.Format(_T("%d"), s.id);
out_str =out_str + "ID:" + str + " ";
str = s.name;
out_str = out_str+ "姓名:" + str + " ";
str.Format(_T("%.1f"), s.s_english);
out_str = out_str + "英语:" + str + " ";
str.Format(_T("%.1f"), s.s_math);
out_str = out_str + "数学:" + str + " ";
str.Format(_T("%.1f"), s.s_chinese);
out_str = out_str + "语文:" + str;
out_LPT = out_str.GetBuffer();
cout << "name" << endl;
outtextxy(0, 0, out_LPT);
}
效果
4.吐槽
雯饰太一 发布了14 篇原创文章 · 获赞 9 · 访问量 4246 私信 关注本来就是想找个管理系统好好做一做,一直看c++ primer plus有点反胃,然后就看到这个教程,某州教育的,刚开始没发现,还一会会有干活,但是后来就越听越恶心,最主要是,功能不全,而且非常老旧,气死人,中途老师只知道说用什么函数,就是不讲为什么,简直是差劲的要死,我算是服了,想骂人的冲动已然熊熊燃烧,如果以后会做老师,也会跟这家对着干。
.
下一次再写代码的时候应该边写边做笔记,而不是这样写完之后发现自己好像没怎么出错。
.
遇到类型转换的东西,不能慌,也别乱,看到长文就不想看,这样是不行的,可是事实就是这样。
.
另外,需要实现检测输入以及文件写入的功能
备注:原工程文件[其实上面有,多加一个入口,方便以后使用]
备注:如果转载,请著名来源以及作者。