程序代码:
#include <Windows.h> #include <vector> #include <string> #include <locale> #include <algorithm> #include <numeric> #include <conio.h> #include "myConsole.h" using namespace std; // 学生信息数据结构 struct Student_Info { int ID; // 学号 wchar_t Name[11]; // 姓名 double Scores[4]; // 学科成绩 }; // 表格数据结构 struct Column_Info { wchar_t Caption[20]; // 标题名 wchar_t Separate; // 分隔符 size_t Width; // 栏宽 }; // 游标数据结构 struct Pointer_Info { int Row; // 行号 vector<Student_Info>::iterator current; // 指向的记录 }; // 全局变量 const Column_Info Columns[] = { { L"学号", L'=', 4 }, { L" 姓名 ", L'=', 10 }, { L" 语文 ", L'=', 8 }, { L" 数学 ", L'=', 8 }, { L" 英语 ", L'=', 8 }, { L" 计算机 ", L'=', 8 } }; const wstring FileName(L"Students.dat"); const wstring Tips1(L"Esc:结束 Enter:编辑 Ins:增加 Del:删除 F2:存盘 F3:读盘 F4:排序"); const SMALL_RECT DataRect = { 4, 0, 79, 23 }; const SMALL_RECT TipsRect = { 0, 24, 79, 24 }; const int PageRecords(DataRect.Bottom - DataRect.Top - 2); myConsole Console(GetStdHandle(STD_OUTPUT_HANDLE)); vector<Student_Info> Students; Pointer_Info Pointer; // 函数原型 void Show_Tips(const wstring tips); void Set_Pointer(Pointer_Info& pointer, bool on); void Show_Data(const vector<Student_Info>::iterator first); void Append_Data(void); void Edit_Data(const vector<Student_Info>::iterator current, int row); bool Save_Data(const wchar_t file_name[]); bool Load_Data(const wchar_t file_name[]); bool IsGreater(const Student_Info& lhs, const Student_Info& rhs); // 程序入口 int wmain(int argc, wchar_t *argv[], wchar_t *envp[]) { setlocale(LC_ALL, "chs"); if (!Load_Data(FileName.c_str())) { wprintf_s(L"文件%s打开失败,请检查再试。\n", FileName.c_str()); Console.ReadKey(); return EXIT_FAILURE; } Console.SetTitle(L"学生成绩处理"); Console.Cls(myConsole::ForeWhite | myConsole::BackDarkBlue); Show_Tips(Tips1); bool refresh(true); bool finish(false); Console.SetCursorVisible(false); vector<Student_Info>::iterator first(Students.begin()); Pointer.Row = 0; Pointer.current = first; Set_Pointer(Pointer, true); while (!finish) { if (refresh) { Show_Data(first); refresh = false; } if (_kbhit()) { WCHAR key(Console.ReadKey()); switch (key) { case myConsole::K_DOWN: if (Pointer.current != Students.end() - 1) { Set_Pointer(Pointer, false); if (Pointer.Row < PageRecords) { ++Pointer.Row; } else { ++first; refresh = true; } ++Pointer.current; Set_Pointer(Pointer, true); } break; case myConsole::K_UP: if (Pointer.current != Students.begin()) { Set_Pointer(Pointer, false); if (Pointer.Row > 0) { --Pointer.Row; } else { --first; refresh = true; } --Pointer.current; Set_Pointer(Pointer, true); } break; case myConsole::K_HOME: Set_Pointer(Pointer, false); Pointer.current = Students.begin(); Pointer.Row = 0; Set_Pointer(Pointer, true); first = Students.begin(); refresh = true; break; case myConsole::K_END: Set_Pointer(Pointer, false); Pointer.current = Students.end() - 1; if (Pointer.current - Students.begin() < PageRecords) { Pointer.Row = Pointer.current - Students.begin(); } else { Pointer.Row = PageRecords; } Set_Pointer(Pointer, true); first = Pointer.current - Pointer.Row; refresh = true; break; case myConsole::K_INS: Set_Pointer(Pointer, false); Append_Data(); Pointer.current = Students.end() - 1; if (Pointer.current - Students.begin() < PageRecords) { Pointer.Row = Pointer.current - Students.begin(); } else { Pointer.Row = PageRecords; } first = Pointer.current - Pointer.Row; Set_Pointer(Pointer, true); refresh = true; break; case myConsole::K_DEL: if (Pointer.current != Students.begin()) { Set_Pointer(Pointer, false); Pointer.current = Students.erase(Pointer.current); if (Pointer.current == Students.end()) { Pointer.current = Students.end() - 1; --Pointer.Row; } Set_Pointer(Pointer, true); refresh = true; } else { Show_Tips(L"不能删除第一条记录! 按<Enter>键返回"); while (Console.ReadKey() != myConsole::K_ENTER) { ; } Show_Tips(Tips1); } break; case myConsole::K_ENTER: Edit_Data(Pointer.current, Pointer.Row); refresh = true; break; case myConsole::K_F2: if (Save_Data(FileName.c_str())) { Show_Tips(L"数据已存盘! 按<Enter>键返回"); while (Console.ReadKey() != myConsole::K_ENTER) { ; } Show_Tips(Tips1); } break; case myConsole::K_F3: Set_Pointer(Pointer, false); refresh = Load_Data(FileName.c_str()); if (refresh) { Pointer.current = Students.begin(); Pointer.Row = 0; first = Pointer.current; } Set_Pointer(Pointer, true); break; case myConsole::K_F4: Set_Pointer(Pointer, false); stable_sort(Students.begin(), Students.end(), IsGreater); Pointer.current = Students.begin(); Pointer.Row = 0; first = Pointer.current; Set_Pointer(Pointer, true); refresh = true; break; case myConsole::K_ESC: finish = true; break; } } } Console.SetCursorVisible(true); Console.SetTextAttribute(myConsole::ForeWhite | myConsole::BackBlack).Cls(); return EXIT_SUCCESS; } void Show_Tips(const wstring tips) { WORD attr(Console.GetTextAttribute()); Console.SetTextAttribute(myConsole::ForeYellow | myConsole::BackRed); Console.Clear(TipsRect); Console.MoveCursor(TipsRect.Left, TipsRect.Top).WriteText(tips); Console.SetTextAttribute(attr); } void Set_Pointer(Pointer_Info& pointer, bool on) { Console.MoveCursor(DataRect.Left - 3, DataRect.Top + 2 + pointer.Row).WriteText(on ? L"→" : L" "); } void Show_Data(const vector<Student_Info>::iterator first) { const WORD attr(Console.GetTextAttribute()); int row, col; Console.Clear(DataRect); // 输出标题 Console.SetTextAttribute(myConsole::ForeGreen | myConsole::BackDarkBlue); row = DataRect.Top; col = DataRect.Left; for (int i = 0; i < _countof(Columns); ++i) { Console.MoveCursor(col, row).WriteText(Columns[i].Caption); wstring s(Columns[i].Width, Columns[i].Separate); Console.MoveCursor(col, row + 1).WriteText(s); col += Columns[i].Width + 2; } ++row; // 输出数据 Console.SetTextAttribute(attr); vector<Student_Info>::difference_type count(0); for (vector<Student_Info>::iterator it = first; (it != Students.end()) && (count++ <= PageRecords); ++it) { col = DataRect.Left; ++row; for (int i = 0; i < _countof(Columns); ++i) { WCHAR buffer[20], format[10]; switch (i) { case 0: swprintf_s(format, L"%%0%dd", Columns[i].Width); swprintf_s(buffer, format, it->ID); break; case 1: wcscpy_s(buffer, it->Name); break; default: swprintf_s(format, L"%%%d.2f", Columns[i].Width); swprintf_s(buffer, format, it->Scores[i-2]); break; } Console.MoveCursor(col, row).WriteText(buffer); col += Columns[i].Width + 2; } } } void Append_Data(void) { Student_Info student; student.ID = Students.size() + 1; student.Name[0] = L'\0'; for (int i = 0; i < _countof(student.Scores); ++i) { student.Scores[i] = 0.0; } Students.push_back(student); } void Edit_Data(const vector<Student_Info>::iterator current, int row) { const WORD attr(Console.GetTextAttribute()); const BOOL cursor(Console.GetCursorVisible()); Console.SetTextAttribute(myConsole::ForeRed | myConsole::BackGreen); Console.SetCursorVisible(true); int x(DataRect.Left); int y(DataRect.Top + 2 + row); for (int i = 0; i < _countof(Columns); ++i) { Console.MoveCursor(x, y); WCHAR buffer[20]; switch (i) { case 0: swprintf_s(buffer, L"%d", current->ID); Console.ReadString(buffer, Columns[i].Width); swscanf_s(buffer, L"%d", &(current->ID)); break; case 1: Console.ReadString(current->Name, Columns[i].Width); break; default: swprintf_s(buffer, L"%.2f", current->Scores[i-2]); Console.ReadString(buffer, Columns[i].Width); swscanf_s(buffer, L"%lf", &(current->Scores[i-2])); break; } x += Columns[i].Width + 2; } Console.SetCursorVisible(cursor); Console.SetTextAttribute(attr); } bool Save_Data(const wchar_t file_name[]) { FILE* file; errno_t error = _wfopen_s(&file, file_name, L"wb"); if ( error == 0) { for (vector<Student_Info>::iterator it = Students.begin(); it != Students.end(); ++it) { fwrite(&(*it), sizeof(Student_Info), 1, file); } fclose(file); } return error == 0; } bool Load_Data(const wchar_t file_name[]) { FILE* file; errno_t error = _wfopen_s(&file, file_name, L"rb"); if (error == 0) { Students.clear(); Student_Info student; while (!feof(file) && (fread(&student, sizeof(student), 1, file) == 1)) { Students.push_back(student); } fclose(file); } return error == 0; } bool IsGreater(const Student_Info& lhs, const Student_Info& rhs) { double sum1(0.0); double sum2(0.0); for (int i = 0; i < _countof(Columns) - 2; ++i) { sum1 += lhs.Scores[i]; sum2 += rhs.Scores[i]; } return sum1 > sum2; }