漂亮的C++控制台界面(格式化输入输出)

来源:互联网 发布:网络语555… 编辑:程序博客网 时间:2024/06/03 01:17

快要放假了,作为一个萌萌嗒的软件专业的小学生,终于要和“课设”这个家伙说hello了~
但是学校总是让做一些系统,比如图书管理系统啦,成绩管理系统啦,lol段位管理系统啦,炉石卡包管理系统啦。。。哈哈,又在瞎掰了,竟然被你们看出来了害羞~
可是我觉得这虽然能够锻炼我们的编程能力,但是界面一点都不美观,一直黑不隆咚的,觉得好别扭。于是突发奇想,可不可以自己写一个类,然后提供一些方法,便于生成漂亮的界面呢,说干就干~~~

先来亮一下输出界面吧:




怎么样,是不是比以前看到的漂亮多了,那它是怎么实现的呢?


void H_Student::showInfo(){IO_Table io;io.setNavigation("学生类型,学生ID,学生姓名,性别,年龄,班级",6);io.setTitle("学生管理系统");H_Student *temp;for (temp = mHead; temp != NULL; temp = temp->mNext){string data[] = { "大学生", to_string(temp->mID), string(temp->mName),string(((temp->mSex == 1) ? "男" : "女")), to_string(temp->mAge), to_string(temp->mClass) };io.addRow(data);}temp = NULL;}


再看看输入界面:




IO_Table io;string data[] = { "学生类型", " 学生ID", " 学生姓名", "性别", "年龄", "班级" };io.inputData(data,6);

就这么简单的几行代码,是不是很方便呢?


下面来看下这个类的实现方法~

这是头文件IO_Table.h:

#pragma once#include <windows.h>#include <string>#include <iostream>#include <iomanip>using namespace std;class IO_Table{public:/*********************************┌───────┬───────┐│ 标题1 │ 标题2 │├───────┼───────┤│ 内容1 │ 内容2 │└───────┴───────┘*********************************/private:typedef struct DATA{string *mRowData;struct DATA *mNext;}Data;static Data *mHead;static Data *mTemp;private:int mLeft;//起始x坐标(为了居中显示,所以动态获取)static const int mTop = 1;//起始y坐标int mRow;//逻辑行数int mCol;//逻辑列数static int *mWidth;//每一列的宽度int mAllWidth;//总宽度(包括边框)static string *mInput;//输入内容string mTitle;//标题private:HANDLE mHand;//控制台句柄static CONSOLE_CURSOR_INFO cursor_true ;//光标可见static CONSOLE_CURSOR_INFO cursor_false;//光标不可见void gotoxy(int x,int y);//广角定位int getAllWidth();//获取表格总宽度(包括边框)void printNavigation(string *navigation);//打印导航栏void printRow(string *content);//打印行void refresh();//刷新void clear();//清空void delPoint(Data*);//删除某个节点public:IO_Table(void);//构造函数~IO_Table();//析构函数void setTitle(string title);//设置标题栏/************************************************************** 对于char型数组,可以用string(char *)转换成为string类型* 对于其他的数据类型,可以利用to_string()函数来转换到string类型*************************************************************/void setNavigation(string *navigation, int col);//设置导航栏void setNavigation(string navigation, int col);//设置导航栏void addRow(string *content);//插入一整行//用完以后一定要用delete[]删除,切记切记!string *inputData(string *navigation, int row);//输入数据string *inputData(string navigation, int row);//输入数据void setInputResult(string strTips);//输入提示};


这是IO_Table.cpp:

#include "IO_Table.h"/*char *mHalo[] = { "──", "┌", "┬", "┐", "├", "┼", "┤", "└", "┴", "┘", "│" }; */IO_Table::Data *IO_Table::mHead = NULL;IO_Table::Data *IO_Table::mTemp = NULL;string *IO_Table::mInput = NULL;//输出初始化int *IO_Table::mWidth = NULL;//宽度初始化CONSOLE_CURSOR_INFO IO_Table::cursor_true = { 5, TRUE };CONSOLE_CURSOR_INFO IO_Table::cursor_false = { 5, FALSE };IO_Table::IO_Table(){clear();mHand = GetStdHandle(STD_OUTPUT_HANDLE);SetConsoleCursorInfo(mHand, &cursor_false);}//==================================设置标题====================================void IO_Table::setTitle(string title){if (mCol == 0) return;mTitle = title;int surplus = title.length() / 2 - (getAllWidth() - 2);gotoxy(mLeft + 1, mTop + 1);//清空标题框cout << setw(getAllWidth()-2) << "";//判断标题文字是否超过最大宽度if (surplus <= 0){SetConsoleTextAttribute(mHand, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY);gotoxy(mLeft + abs(int((getAllWidth() - title.length()/2) / 2)), mTop + 1);cout << title;}else{int minIndex=0;for (int c = 0; c < mCol; c++){mWidth[c] += (surplus / mCol);if (mWidth[minIndex]>mWidth[c]) minIndex = c;}mWidth[minIndex] += surplus % mCol;refresh();SetConsoleTextAttribute(mHand, FOREGROUND_BLUE | FOREGROUND_GREEN | FOREGROUND_INTENSITY);gotoxy(mLeft + (getAllWidth() - title.length() / 2) / 2, mTop + 1);cout << title;}}//=========================添加导航栏=============================void IO_Table::setNavigation(string *navigation, int col){mCol = col;//链表重置,添加导航栏到表头if (mHead != NULL) clear();mHead = mTemp = (Data*)malloc(sizeof(Data));mTemp->mNext = NULL;mTemp->mRowData = new string[col];//宽度重置,根据所给值分配if (mWidth != NULL){delete[] mWidth;mWidth = NULL;}mWidth = new int[mCol];for (int c = 0; c < mCol; c++){mWidth[c] = int(navigation[c].length() / 2 + 0.5);mTemp->mRowData[c] = navigation[c];//把数据存储在链表中}printNavigation(navigation);}void IO_Table::setNavigation(string navigation, int col){mCol = col;//链表重置,添加导航栏到表头if (mHead != NULL) clear();mHead = mTemp = (Data*)malloc(sizeof(Data));mTemp->mNext = NULL;mTemp->mRowData = new string[col];//宽度重置,根据所给值分配if (mWidth != NULL){delete[] mWidth;mWidth = NULL;}mWidth = new int[mCol];string strTemp = "";//临时字符int index = 0;//当前元素for (int c = 0; c < navigation.length(); c++){if (navigation[c] != ',' && navigation[c] != ','){strTemp += navigation[c];}else{mTemp->mRowData[index] = strTemp;mWidth[index] = int(strTemp.length() / 2 + 0.5);strTemp.clear();index++;}}mTemp->mRowData[index] = strTemp;mWidth[index] = int(strTemp.length() / 2 + 0.5);printNavigation(mTemp->mRowData);}//绘制表格边框void IO_Table::printNavigation(string *naviation){system("cls");//每次重绘表头时,行数都归零mRow = 0;//获取水平位置起始点,以居中显示表格mLeft = (40 - getAllWidth()) / 2;SetConsoleTextAttribute(mHand, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);//第1行gotoxy(mLeft, mTop);cout << "┌";for (int c = 0; c < mCol; c++){for (int w = 0; w < mWidth[c]; w++)cout << "─";cout << (c == mCol - 1 ? "┐" : "─");}//第2行gotoxy(mLeft, mTop + 1);cout << "│";cout << setw(getAllWidth()*2 - 4) << "";cout << "│";//第3行gotoxy(mLeft, mTop + 2);cout << "├";for (int c = 0; c < mCol; c++){for (int w = 0; w < mWidth[c]; w++)cout << "─";cout << (c == mCol - 1 ? "┤" : "┬");}//第4行gotoxy(mLeft, mTop + 3);for (int c = 0; c < mCol; c++){cout << "│";SetConsoleTextAttribute(mHand, FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY);cout << setw(mWidth[c]*2) << naviation[c];SetConsoleTextAttribute(mHand, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);}cout << "│";//第5行gotoxy(mLeft, mTop + 4);cout << "└";for (int c = 0; c < mCol; c++){for (int w = 0; w < mWidth[c]; w++)cout << "─";cout << (c == mCol - 1 ? "┘" : "┴");}}//==========================添加行======================================void IO_Table::addRow(string *content){if (mCol == 0) return;bool needRefresh = false;//是否需要刷新(当某个数据超过当前列的宽度时需要刷新)if (mHead == NULL)return;//如果没有表头,直接退出else{mTemp->mNext = (Data*)malloc(sizeof(Data));mTemp = mTemp->mNext;mTemp->mNext = NULL;}mTemp->mRowData = new string[mCol];for (int c = 0; c < mCol; c++){mTemp->mRowData[c] = content[c];if ((content[c].length()/2) > mWidth[c]){mWidth[c] = (content[c].length() % 2 == 0 ? content[c].length()/2 : content[c].length()/2 + 1);needRefresh = true;}}if (needRefresh)refresh();elseprintRow(content);}void IO_Table::printRow(string *content){SetConsoleTextAttribute(mHand, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);gotoxy(mLeft, mTop + mRow * 2 + 4);cout << "├";for (int c = 0; c < mCol; c++){for (int w = 0; w < mWidth[c] ; w++) cout << "─";cout << (c == mCol - 1 ? "┤" : "┼");}gotoxy(mLeft, mTop + mRow * 2 + 5);for (int c = 0; c < mCol; c++){cout << "│";SetConsoleTextAttribute(mHand, 0x0f);cout << setw(mWidth[c]*2) << content[c];SetConsoleTextAttribute(mHand, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);}cout << "│";gotoxy(mLeft, mTop + mRow * 2 + 6);cout << "└";for (int c = 0; c < mCol; c++){for (int w = 0; w < mWidth[c] ; w++) cout << "─";cout << (c == mCol - 1 ? "┘" : "┴");}mRow++;}//===========================输入=================================string *IO_Table::inputData(string *navigation, int row/*数据个数*/){clear();system("cls");mRow = row;mLeft = 10;for (int r = 0; r <= mRow; r++){SetConsoleTextAttribute(mHand, FOREGROUND_RED | FOREGROUND_GREEN |FOREGROUND_INTENSITY);gotoxy(mLeft, mTop + r * 2 );cout << (r == 0 ? "┌" : "├");for (int c = 0; c < 20; c++){cout << (c == 5 ? (r == 0 ? "┬" : (r == mRow ? "┴" : "┼")) : "─");}cout << (r == 0 ? "┐" : "┤");gotoxy(mLeft, mTop + r * 2 + 1);cout << "│";if (r != mRow){SetConsoleTextAttribute(mHand, FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY);cout << setw(10) << navigation[r];SetConsoleTextAttribute(mHand, FOREGROUND_RED | FOREGROUND_GREEN |FOREGROUND_INTENSITY);cout << "│";cout << setw(28) << "";}elsecout << setw(40) << "";cout << "│";gotoxy(mLeft, mTop + r * 2 + 2);cout << "└";for (int c = 0; c < 20; c++)cout << (c == 5 && r != mRow ? "┴" : "─");cout << "┘";}int index = 0;//当前输入焦点行string strTemp;//临时数据的数据string *strInput = new string[row];//所有输入数据的集合SetConsoleCursorInfo(mHand, &cursor_true);SetConsoleTextAttribute(mHand, 0x0f);do{gotoxy(mLeft + 7, mTop + index * 2 + 1);fflush(stdin);getline(cin, strTemp);if (strTemp.length() == 0) continue;strInput[index] = strTemp;} while (++index < row);SetConsoleCursorInfo(mHand, &cursor_false);gotoxy(mLeft + 1, mTop + index * 2 + 1);SetConsoleTextAttribute(mHand, 0x0f);cout << "  输入成功!  请按任意键继续...";return strInput;}string *IO_Table::inputData(string navigation, int row){clear();system("cls");int width = 5;mRow = row;mLeft = 10;string *strNavigation = new string[row];string strTemp = "";//临时字符int index = 0;//当前元素for (int c = 0; c < navigation.length(); c++){if (navigation[c] != ',' && navigation[c] != ','){strTemp += navigation[c];}else{width = width < strTemp.length()/2 ? width : strTemp.length()/2;strNavigation[index++] = strTemp;strTemp.clear();}}strNavigation[index] = strTemp;width = width < strTemp.length()/2 ? width : strTemp.length()/2;for (int r = 0; r <= mRow; r++){SetConsoleTextAttribute(mHand, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);gotoxy(mLeft, mTop + r * 2);cout << (r == 0 ? "┌" : "├");for (int c = 0; c < 20; c++){cout << (c == width ? (r == 0 ? "┬" : (r == mRow ? "┴" : "┼")) : "─");}cout << (r == 0 ? "┐" : "┤");gotoxy(mLeft, mTop + r * 2 + 1);cout << "│";if (r != mRow){SetConsoleTextAttribute(mHand, FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY);cout << setw(10) << strNavigation[r];SetConsoleTextAttribute(mHand, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);cout << "│";cout << setw(28) << "";}elsecout << setw(40) << "";cout << "│";gotoxy(mLeft, mTop + r * 2 + 2);cout << "└";for (int c = 0; c < 20; c++)cout << (c == width && r != mRow ? "┴" : "─");cout << "┘";}delete[] strNavigation;index = 0;//当前输入焦点行string *strInput = new string[row];//所有输入数据的集合SetConsoleCursorInfo(mHand, &cursor_true);SetConsoleTextAttribute(mHand, 0x0f);do{gotoxy(mLeft + 7, mTop + index * 2 + 1);fflush(stdin);getline(cin, strTemp);if (strTemp.length() == 0)continue;strInput[index] = strTemp;} while (++index < row);setInputResult("输入成功!");return strInput;}void IO_Table::setInputResult(string strTips){if (mRow == 0) return;SetConsoleCursorInfo(mHand, &cursor_false);gotoxy(mLeft + 1, mTop + mRow * 2 + 1);cout << setw(40) << "";gotoxy(mLeft + 1, mTop + mRow * 2 + 1);SetConsoleTextAttribute(mHand, 0x0f);cout << strTips;}void IO_Table::refresh(){Data *temp;for (temp = mHead; temp != NULL; temp = temp->mNext){if (temp == mHead)printNavigation(temp->mRowData);elseprintRow(temp->mRowData);}if (!mTitle.empty()) setTitle(mTitle);}inline void IO_Table::gotoxy(int x, int y){COORD cd;cd.X = x << 1;cd.Y = y;SetConsoleCursorPosition(mHand,cd);}int IO_Table::getAllWidth(){int allWidth = mCol + 1;for (int c = 0; c < mCol; c++)allWidth += mWidth[c];return allWidth;}void IO_Table::clear(){mRow = 0;mCol = 0;mLeft = 0;if (mWidth != NULL){delete[] mWidth;mWidth = NULL;}if (mInput != NULL){delete[] mInput;mInput = NULL;}Data *next;mTemp = mHead;while (mTemp != NULL){//先把行数据清空delete[] mTemp->mRowData;mTemp->mRowData = NULL;//释放节点并删除next = mTemp->mNext;free(mTemp);mTemp = next;}mHead = mTemp = next = NULL;}IO_Table::~IO_Table(){clear();}

现在呢,它不仅可以格式化输出,还可以格式化输入,并且可以根据数据的长度自由控制表格的宽度,标题和表格都是居中显示的。但是,它也有一些缺点,就是如果数据过于长且超过窗口的最大宽度,它会乱行吐舌头

由于技术有限,目前只能写到这里,当然程序中一定会有一些bug,所以这里分享给大家,希望大家能够和我一起改进它,让它成为一个可以被广泛使用的类。



2 0
原创粉丝点击