C++控制台强化如何实现一定界面效果(简洁版)
TANXL_CONSOLE_LIST VERSION_1_4
在完成了游戏存档模块的开发之后,我试图用之前制作的Console_List头文件为基础,制作一个命令行上的数据管理器,但是在实际使用中我发现了Console_List的各种不足。
比如提供了接口之后还需要用户输入大量的代码来完成表格的输出,明显不能做到让接口容易被正确使用,不易被误用。
于是在这个背景下,我对Console_List进行了完全重写,在比前几代代码减少2/3的情况下,功能大幅加强,同时只需要一次物品初始化,一次调用显示函数,明显更加容易使用。
TANXL_CONSOLE_LIST.H VERSION_1_4
#ifndef TANXL_CONSOLE_LIST
#define TANXL_CONSOLE_LIST
#ifndef TANXL_LIST//检查是否使用了其他版本的TANXL_CONSOLE_LIST
#define TANXL_LIST
#define LIST 1
#endif
#endif
#if LIST
#ifndef iOSTREAM//检查是否已经包含IOSTREAM
#define IOSTREAM
#include <iostream>
#endif
#ifndef VECTOR//检查是否已经包含VECTOR
#define VECTOR
#include <vector>
#endif
#ifndef CONIO_H//检查是否已经包含CONIO_H
#define CONIO_H
#include <conio.h>
#endif
#ifndef IOMANIP//检查是否已经包含IOMANIP
#define IOMANIP
#include <iomanip>
#endif
//void Col是原Console_List的核心功能,使用了linux控制台的指令
void Col(unsigned ColN = NULL, bool Under_Line = false)//设置自定义行的背景颜色
{
if (ColN == NULL)std::cout << "\033[0m";//清除颜色
else
{
if (Under_Line == true)
std::cout << "\033[7m";
std::cout << "\033[4;1;m";
if (((ColN & 0xf0) >> 4) > 0 && ((ColN & 0xf0) >> 4) <= 7)
std::cout << "\033[3" << ((ColN & 0xf0) >> 4) << "m";
else if ((ColN & 0xf0) >> 4 == 0);//值为0不作修改
else//字体颜色: 1红色 2绿色 3橙色 4蓝色 5紫色 6淡蓝 7白色
std::cout << "\033[3" << rand() % 7 + 1 << "m";
if ((ColN & 0x0f) > 0 && ((ColN & 0x0f) <= 7))
std::cout << "\033[4" << (ColN & 0x0f) << "m";
else if ((ColN & 0x0f) == 0);//值为0不作修改
else//背景颜色: 1红色 2绿色 3橙色 4蓝色 5紫色 6淡蓝 7白色
std::cout << "\033[4" << rand() % 7 + 1 << "m";
}
}
//第三级别的物品结构
struct Function
{
//void Page_Info() { Col(); std::cout << "This: " << Selector << " - Total: " << SonList.size() << " - Max: " << (SSpace & 0x0000ff) << std::endl; }
Function() :Name("NULL"), Func(NULL) {};
Function(std::string N, void(*F)()) :Name(N), Func(F) {};
//int Selector{ 0 };
//bool Is_Selected{ false };
std::string Name;
void(*Func)();
unsigned SSpace{ 0x171109 };//选项和标题的空格数 AA-BB-CC AA左空格 BB右空格 CC页面物品限制数量
//std::vector<Function>SonList;
};
//第二级别的物品结构
struct Main_Function
{
void Page_Info() { Col(); std::cout << "This: " << Selector << " - Total: " << SonList.size() << " - Max: " << (SSpace & 0x0000ff) << std::endl; }
Main_Function(std::string N = "NULL") :Name(N), SonList(NULL) {};
Main_Function(std::string N, void(*F)()) :Name(N), SonList(NULL), Func(F) {};
int Selector{ 0 };
bool Is_Selected{ false };
std::string Name;
void(*Func)() { NULL };
unsigned SSpace{ 0x171109 };//选项和标题的空格数 AA-BB-CC AA左空格 BB右空格 CC页面物品限制数量
std::vector<Function>SonList;
};
//第一级别的主要物品类
class CONSOLE_LIST
{
public:
void Display();
void Append_Item(std::string New_Item) { SonList.push_back(Main_Function(New_Item)); };//添加二级物品作为选项
//At用于指定第几个二级物品,后续两个量用于生成一个新的三级物品
void Append_Svec(int At, std::string Name, void(*Func)()) { SonList.at(At).SonList.push_back(Function(Name, Func)); };//添加二级物品下的三级物品,同时绑定一个void类型的函数
private:
void Page_Info() { Col(); std::cout << "This: " << Selector << " - Total: " << SonList.size() << " - Max: " << (SSpace & 0x0000ff) << std::endl; }//输出当前页面信息
bool Insert_Action(int* Action_Num, bool* Action_Bol, size_t List_Size);//输入操作
int Selector{ 0 };
int Pages{ 0 };
bool Is_Selected{ false };
std::vector<Main_Function>SonList;
unsigned SSpace{ 0x171109 };//选项和标题的空格数 AA-BB-CC AA左空格 BB右空格 CC页面物品限制数量
};
void CONSOLE_LIST::Display()
{
Col();
bool flag{ true };
bool brea{ false };
while (true)
{
if (!flag)
{
Is_Selected = false;
flag = true;
continue;
}
system("cls");
int* Num{ &Selector };
bool* Bol{ &Is_Selected };
size_t Siz{ SonList.size() };
for (int i = 0; i < SonList.size(); i++)
{
if (i == Selector)
Col(0x71);
else
Col(0x17);
std::cout << std::setw((SSpace & 0xff0000) >> 16) << SonList.at(i).Name << std::setw((SSpace & 0x00ff00) >> 8) << " " << std::endl;
if (i == Selector && Is_Selected == true)
{
Pages = SonList.at(i).Selector / (SSpace & 0x0000ff);
for (int j = Pages * (SSpace & 0x0000ff), count = 0; j < SonList.at(i).SonList.size() && count < (SSpace & 0x0000ff); j++&& count++)
{
if (j == SonList.at(i).Selector)
Col(0x71);
else
Col(0x17);
std::cout << std::setw((SSpace & 0xff0000) >> 16) << SonList.at(i).SonList.at(j).Name << std::setw((SSpace & 0x00ff00) >> 8) << " " << std::endl;
if (SonList.at(i).Is_Selected == true && j == SonList.at(i).Selector)
{
SonList.at(i).SonList.at(j).Func();
SonList.at(i).Is_Selected = false;
brea = true;
break;
}
}
SonList.at(i).Page_Info();
if (brea)
break;
Num = &SonList.at(i).Selector;
Bol = &SonList.at(i).Is_Selected;
Siz = SonList.at(i).SonList.size();
}
std::cout << std::endl;
}
Page_Info();
if (brea)
{
brea = false;
continue;
}
Col();
flag = Insert_Action(Num, Bol, Siz);//等待输入
}
}
bool CONSOLE_LIST::Insert_Action(int* Action_Num, bool* Action_Bol, size_t List_Size)
{
char key = _getch();
if (key == 'c' || key == 'C')//如果输入了大小写的C则返回上一级
{
*Action_Bol = false;
return false;
}
if (static_cast<int>(key - 48) >= 0 && static_cast<int>(key - 48) <= 9)//判断是否是从零到九的数字
{
if (static_cast<int>(key - 48) <= List_Size)//如果是,且小于等于选项总数则直接指定这个选项
*Action_Num = static_cast<int>(key - 48) - 1;
else
*Action_Num = static_cast<int>(List_Size) - 1;//如果超出了最大值,则指向最大值
*Action_Bol = true;
}
else if (key == 'w' || key == 'W' || key == 72)//如果输入了大小写的W或者上箭头,则执行MoveUp函数
*Action_Num = *Action_Num == 0 ? static_cast<int>(List_Size) - 1 : -- * Action_Num;
else if (key == 's' || key == 'S' || key == 80)//如果输入了大小写的S或者下箭头,则执行MoveDown函数
*Action_Num = *Action_Num == static_cast<int>(List_Size) - 1 ? 0 : ++ * Action_Num;
else if (key == 'a' || key == 'A' || key == 75)//如果输入了大小写的A或者左箭头,则执行向上翻页函数
*Action_Num = *Action_Num - static_cast<int>(SSpace & 0x0000ff) < 0 ? 0 : *Action_Num - (SSpace & 0x0000ff);
else if (key == 'd' || key == 'D' || key == 77)//如果输入了大小写的D或者右箭头,则执行向下翻页函数
*Action_Num = *Action_Num + (SSpace & 0x0000ff) > static_cast<int>(List_Size) - 1 ? static_cast<int>(List_Size) - 1 : *Action_Num + (SSpace & 0x0000ff);
else if (key == '\r')//回车确认
*Action_Bol = true;
return true;
}
#endif
以下为使用例:
Main.cpp
#include "TANXL_CONSOLE_LIST.h"
void say()
{
Col();
system("cls");
std::cout << "wdnmd";
system("pause");
}
int main()
{
CONSOLE_LIST TSM;
TSM.Append_Item("数据管理");
TSM.Append_Svec(0, "数据管理1", &say);
TSM.Append_Svec(0, "数据管理2", &say);
TSM.Append_Svec(0, "数据管理3", &say);
TSM.Append_Svec(0, "数据管理4", &say);
TSM.Append_Svec(0, "数据管理5", &say);
TSM.Append_Svec(0, "数据管理6", &say);
TSM.Append_Svec(0, "数据管理7", &say);
TSM.Append_Svec(0, "数据管理8", &say);
TSM.Append_Svec(0, "数据管理9", &say);
TSM.Append_Svec(0, "数据管理10", &say);
TSM.Append_Svec(0, "数据管理11", &say);
TSM.Append_Svec(0, "数据管理12", &say);
TSM.Append_Svec(0, "数据管理13", &say);
TSM.Append_Svec(0, "数据管理14", &say);
TSM.Append_Svec(0, "数据管理15", &say);
TSM.Append_Item("添加数据");
TSM.Append_Svec(1, "添加数据1", &say);
TSM.Append_Svec(1, "添加数据2", &say);
TSM.Append_Svec(1, "添加数据3", &say);
TSM.Append_Item("查看数据");
TSM.Append_Svec(2, "查看数据1", &say);
TSM.Append_Svec(2, "查看数据2", &say);
TSM.Append_Svec(2, "查看数据3", &say);
TSM.Append_Item("修改数据");
TSM.Append_Svec(3, "修改数据1", &say);
TSM.Append_Svec(3, "修改数据2", &say);
TSM.Append_Svec(3, "修改数据3", &say);
TSM.Append_Item("退出程序");
TSM.Append_Svec(4, "_-确认-_", &say);
TSM.Append_Svec(4, "_-取消-_", &say);
TSM.Display();
}
TANXL_CONSOLE_LIST.H VERSION_1_5
再次对几乎所有函数进行重写,为了操作的一致性移除了三级物品的设定,统一由类来进行管理。通过递归的方法实现输出列表,理论上能无限扩展深度。
三级列表
六级列表
TANXL_CONSOLE_LIST.H VERSION_1_5
// 移除Main_Function Function并将功能整合至CONSOLE类
// 绝大多数函数重写以支持多于一层的表格输出
#ifndef TANXL_CONSOLE_LIST
#define TANXL_CONSOLE_LIST
#ifndef TANXL_LIST//检查是否使用了其他版本的TANXL_CONSOLE_LIST
#define TANXL_LIST
#define LIST 1
#endif
#endif
#if LIST
#ifndef IOSTREAM//检查是否已经包含IOSTREAM
#define IOSTREAM
#include <iostream>
#endif
#ifndef VECTOR//检查是否已经包含VECTOR
#define VECTOR
#include <vector>
#endif
#ifndef CONIO_H//检查是否已经包含CONIO_H
#define CONIO_H
#include <conio.h>
#endif
#ifndef IOMANIP//检查是否已经包含IOMANIP
#define IOMANIP
#include <iomanip>
#endif
//void Col是原Console_List的核心功能,使用了Linux控制台的指令
void Col(unsigned ColN = NULL, bool Under_Line = false);//设置自定义行的背景颜色
//物品类
class CONSOLE
{
public:
explicit CONSOLE(std::string Name = "UNdefined", unsigned Space = 0x171109, void(*FunC)() = NULL);
void Display(int Depth = 0, unsigned Def_Col = 0x71, unsigned Real_Sel = 0x75);
void MainLoop();
void Append_Item(std::string New_Item, unsigned Col, void(*FunC)(), int Depth = 0, int* Ids = 0);
private:
bool Insert_Action(int* Action_Num, bool* Action_Bol, size_t List_Size);
CONSOLE* Locate(int Target = 0);
std::string Name;
int Selector;
int Page;
bool Is_Selected;
bool Is_Funcwork;
std::vector<CONSOLE>SonList;
void (*Func)();
unsigned SSpace;// { 0x171109 }选项和标题的空格数 AA-BB-CC AA左空格 BB右空格 CC页面物品限制数量
};
#endif
TANXL_CONSOLE_LIST.CPP VERSION_1_5
#include "TANXL_CONSOLE_LIST.h"
//void Col是原Console_List的核心功能,使用了Linux控制台的指令
void Col(unsigned ColN, bool Under_Line)//设置自定义行的背景颜色
{
if (ColN == NULL)std::cout << "\033[0m";//清除颜色
else
{
if (Under_Line == true)
std::cout << "\033[7m";
std::cout << "\033[4;1;m";
if (((ColN & 0xf0) >> 4) > 0 && ((ColN & 0xf0) >> 4) <= 7)
std::cout << "\033[3" << ((ColN & 0xf0) >> 4) << "m";
else if ((ColN & 0xf0) >> 4 == 0);//值为0不作修改
else//字体颜色: 1红色 2绿色 3橙色 4蓝色 5紫色 6淡蓝 7白色
std::cout << "\033[3" << rand() % 7 + 1 << "m";
if ((ColN & 0x0f) > 0 && ((ColN & 0x0f) <= 7))
std::cout << "\033[4" << (ColN & 0x0f) << "m";
else if ((ColN & 0x0f) == 0);//值为0不作修改
else//背景颜色: 1红色 2绿色 3橙色 4蓝色 5紫色 6淡蓝 7白色
std::cout << "\033[4" << rand() % 7 + 1 << "m";
}
}
//构造函数
CONSOLE::CONSOLE(std::string NamE, unsigned Space, void(*FunC)())
:Selector(0), Is_Selected(false), SonList(NULL), SSpace(Space), Func(FunC), Is_Funcwork(true), Name(NamE),Page(0)
{
if (Func == NULL)
Is_Funcwork = false;
}
//添加函数
void CONSOLE::Append_Item(std::string New_Item, unsigned Col, void (*FunC)(), int Depth, int* Ids)
{
if (Depth == 0)
SonList.push_back(CONSOLE(New_Item, Col, FunC));
else
{
CONSOLE* CP{ this };
for (int i = 0; i < Depth; i++)
CP = &CP->SonList.at(Ids[i]);
CP->SonList.push_back(CONSOLE(New_Item, Col, FunC));
}
}
void CONSOLE::Display(int Depth, unsigned Def_Col, unsigned Real_Sel)
{
Col();
bool Is_Line_Need{ false };
Page = this->Selector / (SSpace & 0x00ff);
for (int i = Page * (SSpace & 0x00ff); i < SonList.size() && i < (Page+1)*(SSpace & 0x00ff); i++)
{
for (int j = Depth; j > 0; j--)
std::cout << "\t";
if (i == Selector)
Col(Real_Sel);
else
Col(Def_Col);
std::cout << std::setw((SSpace & 0xff0000) >> 16) << SonList.at(i).Name << std::setw((SSpace & 0x00ff00) >> 8) << " " << std::endl;
Col();
if (SonList.at(i).SonList.size() == 0 && this->Is_Selected == true && this->Selector == i)//在包含子项目为0时自动退出
{
if (SonList.at(i).Is_Funcwork)
SonList.at(i).Func();
this->Is_Selected = false;
}
if (SonList.at(i).SonList.size() != 0 && this->Is_Selected == true && this->Selector == i)
{
std::cout << std::endl;
this->SonList.at(i).Display(Depth + 1, (Def_Col & 0x0f) * 16 + (Def_Col & 0xf0) / 16, Real_Sel);
Is_Line_Need = 1;
}
if (!Is_Line_Need)
std::cout << std::endl;
if (Is_Line_Need)
Is_Line_Need = false;
Col();
}
}
void CONSOLE::MainLoop()//主循环
{
bool Insert{ true };
bool Cover{ false };
int* Action_Num { &Locate()->Selector};
bool* Action_Bol{ &Locate()->Is_Selected };
size_t List_Size{ Locate()->SonList.size() };
while (1)
{
system("cls");
this->Display();
if (!Cover)
{
Action_Num = &Locate()->Selector;
Action_Bol = &Locate()->Is_Selected;
List_Size = Locate()->SonList.size();
}
else
Cover = false;
if (!Insert)
{
Action_Num = &Locate(-1)->Selector;
Action_Bol = &Locate(-1)->Is_Selected;
List_Size = Locate(-1)->SonList.size();
Locate(-1)->Is_Selected = false;
Insert = true;
Cover = true;
continue;
}
Insert = Insert_Action(Action_Num, Action_Bol, List_Size);
}
}
bool CONSOLE::Insert_Action(int* Action_Num, bool* Action_Bol, size_t List_Size)
{
char key = _getch();
if (key == 'c' || key == 'C')//如果输入了大小写的C则返回上一级
{
*Action_Bol = false;
return false;
}
if (static_cast<int>(key - 48) >= 0 && static_cast<int>(key - 48) <= 9)//判断是否是从零到九的数字
{
if (static_cast<int>(key - 48) <= static_cast<int>(List_Size))//如果是,且小于等于选项总数则直接指定这个选项
*Action_Num = static_cast<int>(key - 48) - 1;
else
*Action_Num = static_cast<int>(List_Size) - 1;//如果超出了最大值,则指向最大值
*Action_Bol = true;
}
else if (key == 'w' || key == 'W' || key == 72)//如果输入了大小写的W或者上箭头,则执行MoveUp函数
*Action_Num = *Action_Num == 0 ? static_cast<int>(List_Size) - 1 : -- * Action_Num;
else if (key == 's' || key == 'S' || key == 80)//如果输入了大小写的S或者下箭头,则执行MoveDown函数
*Action_Num = *Action_Num == static_cast<int>(List_Size) - 1 ? 0 : ++ * Action_Num;
else if (key == 'a' || key == 'A' || key == 75)//如果输入了大小写的A或者左箭头,则执行向上翻页函数
*Action_Num = *Action_Num - static_cast<int>(SSpace & 0x0000ff) < 0 ? 0 : *Action_Num - (SSpace & 0x0000ff);
else if (key == 'd' || key == 'D' || key == 77)//如果输入了大小写的D或者右箭头,则执行向下翻页函数
*Action_Num = *Action_Num + static_cast<int>(SSpace & 0x0000ff) > static_cast<int>(List_Size) - 1 ? static_cast<int>(List_Size) - 1 : *Action_Num + (SSpace & 0x0000ff);
else if (key == '\r')//回车确认
*Action_Bol = true;
return true;
}
CONSOLE* CONSOLE::Locate(int Target)
{
if (Target == 0)
{
for (int i = 0; i < SonList.size(); i++)
{
if (i == Selector && Is_Selected == true)
return SonList.at(i).Locate();
}
return this;
}
else
{
for (int i = 0; i < SonList.size(); i++)
{
if (i == Selector && Is_Selected == true && SonList.at(i).SonList.size() != 0)
if (SonList.at(i).Is_Selected == false)
return this;
else
return SonList.at(i).Locate(-1);
}
return this;
}
}
Main.CPP(测试用)
#include "Tanxl_Console_List.h"
void say()
{
Col();
std::cout << "\t\tDefault Function Called" << std::endl;
}
int main()
{
CONSOLE TSM;
TSM.Append_Item("数据管理", 0x171109, &say);
TSM.Append_Item("添加数据", 0x171109, &say);
TSM.Append_Item("查看数据", 0x171109, &say);
TSM.Append_Item("修改数据", 0x171109, &say);
TSM.Append_Item("退出程序", 0x171109, &say);
int a[] = { 2 };
int b[] = { 2,1 };
TSM.Append_Item("数据管理1-", 0x171109, &say, 1, a);
TSM.Append_Item("数据管理2-", 0x171109, &say, 1, a);
TSM.Append_Item("数据管理3-", 0x171109, &say, 1, a);
TSM.Append_Item("数据管理4-", 0x171109, &say, 1, a);
TSM.Append_Item("数据管理5-", 0x171109, &say, 1, a);
TSM.Append_Item("数据管理6-", 0x171109, &say, 1, a);
TSM.Append_Item("数据管理7-", 0x171109, &say, 1, a);
TSM.Append_Item("数据管理8-", 0x171109, &say, 1, a);
TSM.Append_Item("数据管理9-", 0x171109, &say, 1, a);
TSM.Append_Item("数据管理10-", 0x171109, &say, 1, a);
TSM.Append_Item("数据管理11-", 0x171109, &say, 1, a);
TSM.Append_Item("数据管理2-1", 0x171109, &say, 2, b);
TSM.Append_Item("数据管理2-2", 0x171109, &say, 2, b);
TSM.Append_Item("数据管理2-3", 0x171109, &say, 2, b);
TSM.Append_Item("数据管理2-4", 0x171109, &say, 2, b);
TSM.Append_Item("数据管理2-5", 0x171109, &say, 2, b);
TSM.Append_Item("数据管理2-6", 0x171109, &say, 2, b);
TSM.MainLoop();
return 0;
}
TANXL_CONSOLE_LIST.H VERSION_1_5+_Final
// 加入枚举类型用于颜色设置 使之表现更加直观
enum EFont_Color
{
FONT_UNDEFINED = 0x00,
FONT_COLOR_RED = 0x10,
FONT_COLOR_GREEN = 0x20,
FONT_COLOR_ORANGE = 0x30,
FONT_COLOR_BLUE = 0x40,
FONT_COLOR_PURPLE = 0x50,
FONT_COLOR_LIGHTBLUE = 0x60,
FONT_COLOR_WHITE = 0x70
};
enum EBack_Color
{
BACK_UNDEFINED = 0x00,
BACK_COLOR_RED = 0x01,
BACK_COLOR_GREEN = 0x02,
BACK_COLOR_ORANGE = 0x03,
BACK_COLOR_BLUE = 0x04,
BACK_COLOR_PURPLE = 0x05,
BACK_COLOR_LIGHTBLUE = 0x06,
BACK_COLOR_WHITE = 0x07
};
void Display(int Depth = 0, unsigned Def_Col = 0x71, unsigned Real_Sel = 0x75);
//可以改为更直观的 ↓
void Display(int Depth = 0, unsigned Def_Col = FONT_COLOR_WHITE | BACK_COLOR_RED, unsigned Real_Sel = FONT_COLOR_WHITE | BACK_COLOR_PURPLE);
Col(0x71); Col(FONT_COLOR_WHITE | BACK_COLOR_RED);
Col(0x75); Col(FONT_COLOR_WHITE | BACK_COLOR_PURPLE);
TANXL_CONSOLE_LIST.H VERSION_1_5++_Final
细节调整
#ifndef TANXL_CONSOLE_LIST
#define TANXL_CONSOLE_LIST
#ifndef IOSTREAM//检查是否已经包含IOSTREAM
#define IOSTREAM
#include <iostream>
#endif
#ifndef VECTOR//检查是否已经包含VECTOR
#define VECTOR
#include <vector>
#endif
#ifndef CONIO_H//检查是否已经包含CONIO_H
#define CONIO_H
#include <conio.h>
#endif
#ifndef IOMANIP//检查是否已经包含IOMANIP
#define IOMANIP
#include <iomanip>
#endif
enum EFont_Color
{
FONT_UNDEFINED = 0x00,
FONT_COLOR_RED = 0x10,
FONT_COLOR_GREEN = 0x20,
FONT_COLOR_ORANGE = 0x30,
FONT_COLOR_BLUE = 0x40,
FONT_COLOR_PURPLE = 0x50,
FONT_COLOR_LIGHTBLUE = 0x60,
FONT_COLOR_WHITE = 0x70
};
enum EBack_Color
{
BACK_UNDEFINED = 0x00,
BACK_COLOR_RED = 0x01,
BACK_COLOR_GREEN = 0x02,
BACK_COLOR_ORANGE = 0x03,
BACK_COLOR_BLUE = 0x04,
BACK_COLOR_PURPLE = 0x05,
BACK_COLOR_LIGHTBLUE = 0x06,
BACK_COLOR_WHITE = 0x07
};
//void Col是原Console_List的核心功能,使用了Linux控制台的指令
void Col(unsigned ColN = NULL, bool Under_Line = false);//设置自定义行的背景颜色
//物品类
class CONSOLE
{
public:
explicit CONSOLE(std::string Name = "UNdefined", unsigned Space = 0x171109, void(*FunC)() = NULL);
void Display(int Depth = 0, unsigned Def_Col = FONT_COLOR_WHITE | BACK_COLOR_RED, unsigned Real_Sel = FONT_COLOR_WHITE | BACK_COLOR_PURPLE);
void MainLoop(unsigned Def_Col = FONT_COLOR_WHITE | BACK_COLOR_RED, unsigned Real_Sel = FONT_COLOR_WHITE | BACK_COLOR_PURPLE);
void Append_Item(std::string New_Item, unsigned Space = 0x171109, void(*FunC)() = NULL, int Depth = 0, int* Ids = 0);
private:
bool Insert_Action(int* Action_Num, bool* Action_Bol, size_t List_Size);
CONSOLE* Locate(int Target = 0);
std::string Name;
int Selector;
int Page;
bool Is_Selected;
bool Is_Funcwork;
std::vector<CONSOLE>SonList;
void (*Func)();
unsigned SSpace;// { 0x171109 }选项和标题的空格数 AA-BB-CC AA左空格 BB右空格 CC页面物品限制数量
};
#endif
TANXL_CONSOLE_LIST.CPP VERSION_1_5++_Final
#include "TANXL_CONSOLE_LIST.h"
//void Col是原Console_List的核心功能,使用了Linux控制台的指令
void Col(unsigned ColN, bool Under_Line)//设置自定义行的背景颜色
{
if (ColN == NULL)std::cout << "\033[0m";//清除颜色
else
{
if (Under_Line == true)
std::cout << "\033[7m";
std::cout << "\033[4;1;m";
if (((ColN & 0xf0) >> 4) > 0 && ((ColN & 0xf0) >> 4) <= 7)
std::cout << "\033[3" << ((ColN & 0xf0) >> 4) << "m";
else if ((ColN & 0xf0) >> 4 == 0);//值为0不作修改
else//字体颜色: 1红色 2绿色 3橙色 4蓝色 5紫色 6淡蓝 7白色
std::cout << "\033[3" << rand() % 7 + 1 << "m";
if ((ColN & 0x0f) > 0 && ((ColN & 0x0f) <= 7))
std::cout << "\033[4" << (ColN & 0x0f) << "m";
else if ((ColN & 0x0f) == 0);//值为0不作修改
else//背景颜色: 1红色 2绿色 3橙色 4蓝色 5紫色 6淡蓝 7白色
std::cout << "\033[4" << rand() % 7 + 1 << "m";
}
}
//构造函数
CONSOLE::CONSOLE(std::string NamE, unsigned Space, void(*FunC)())
:Selector(0), Is_Selected(false), SonList(NULL), SSpace(Space), Func(FunC), Is_Funcwork(true), Name(NamE),Page(0)
{
if (Func == NULL)
Is_Funcwork = false;
}
//添加函数
void CONSOLE::Append_Item(std::string New_Item, unsigned Space, void (*FunC)(), int Depth, int* Ids)
{
if (Depth == 0)
SonList.push_back(CONSOLE(New_Item, Space, FunC));
else
{
CONSOLE* CP{ this };
for (int i = 0; i < Depth; i++)
CP = &CP->SonList.at(Ids[i]);
CP->SonList.push_back(CONSOLE(New_Item, Space, FunC));
}
}
void CONSOLE::Display(int Depth, unsigned Def_Col, unsigned Real_Sel)
{
Col();
bool Is_Line_Need{ false };
Page = this->Selector / (SSpace & 0x00ff);
for (int i = Page * (SSpace & 0x00ff); i < SonList.size() && i < (Page+1)*(SSpace & 0x00ff); i++)
{
for (int j = Depth; j > 0; j--)
std::cout << "\t";
if (i == Selector)
Col(Real_Sel);
else
Col(Def_Col);
std::cout << std::setw((SSpace & 0xff0000) >> 16) << SonList.at(i).Name << std::setw((SSpace & 0x00ff00) >> 8) << " " << std::endl;
Col();
if (SonList.at(i).SonList.size() == 0 && this->Is_Selected == true && this->Selector == i)//在包含子项目为0时自动退出
{
if (SonList.at(i).Is_Funcwork)
SonList.at(i).Func();
this->Is_Selected = false;
}
if (SonList.at(i).SonList.size() != 0 && this->Is_Selected == true && this->Selector == i)
{
std::cout << std::endl;
this->SonList.at(i).Display(Depth + 1, (Def_Col & 0x0f) * 16 + (Def_Col & 0xf0) / 16, Real_Sel);
Is_Line_Need = 1;
}
if (!Is_Line_Need)
std::cout << std::endl;
if (Is_Line_Need)
Is_Line_Need = false;
Col();
}
}
void CONSOLE::MainLoop(unsigned Def_Col, unsigned Real_Sel)
{
bool Insert{ true };
bool Cover{ false };
int* Action_Num{ &Locate()->Selector };
bool* Action_Bol{ &Locate()->Is_Selected };
size_t List_Size{ Locate()->SonList.size() };
while (1)
{
system("cls");
this->Display();
if (!Cover)
{
Action_Num = &Locate()->Selector;
Action_Bol = &Locate()->Is_Selected;
List_Size = Locate()->SonList.size();
}
else
Cover = false;
if (!Insert)
{
Action_Num = &Locate(-1)->Selector;
Action_Bol = &Locate(-1)->Is_Selected;
List_Size = Locate(-1)->SonList.size();
Locate(-1)->Is_Selected = false;
Insert = true;
Cover = true;
continue;
}
Insert = Insert_Action(Action_Num, Action_Bol, List_Size);
}
}
bool CONSOLE::Insert_Action(int* Action_Num, bool* Action_Bol, size_t List_Size)
{
char key = _getch();
if (key == 'c' || key == 'C')//如果输入了大小写的C则返回上一级
{
*Action_Bol = false;
return false;
}
if (static_cast<int>(key - 48) >= 0 && static_cast<int>(key - 48) <= 9)//判断是否是从零到九的数字
{
if (static_cast<int>(key - 48) <= static_cast<int>(List_Size))//如果是,且小于等于选项总数则直接指定这个选项
*Action_Num = static_cast<int>(key - 48) - 1;
else
*Action_Num = static_cast<int>(List_Size) - 1;//如果超出了最大值,则指向最大值
*Action_Bol = true;
}
else if (key == 'w' || key == 'W' || key == 72)//如果输入了大小写的W或者上箭头,则执行MoveUp
*Action_Num = *Action_Num == 0 ? static_cast<int>(List_Size) - 1 : -- * Action_Num;
else if (key == 's' || key == 'S' || key == 80)//如果输入了大小写的S或者下箭头,则执行MoveDown
*Action_Num = *Action_Num == static_cast<int>(List_Size) - 1 ? 0 : ++ * Action_Num;
else if (key == 'a' || key == 'A' || key == 75)//如果输入了大小写的A或者左箭头,则执行向上翻页
*Action_Num = *Action_Num - static_cast<int>(SSpace & 0x0000ff) < 0 ? 0 : *Action_Num - (SSpace & 0x0000ff);
else if (key == 'd' || key == 'D' || key == 77)//如果输入了大小写的D或者右箭头,则执行向下翻页
*Action_Num = *Action_Num + static_cast<int>(SSpace & 0x0000ff) > static_cast<int>(List_Size) - 1 ? static_cast<int>(List_Size) - 1 : *Action_Num + (SSpace & 0x0000ff);
else if (key == '\r')//回车确认
*Action_Bol = true;
return true;
}
CONSOLE* CONSOLE::Locate(int Target)
{
if (Target == 0)
{
for (int i = 0; i < SonList.size(); i++)
{
if (i == Selector && Is_Selected == true)
return SonList.at(i).Locate();
}
return this;
}
else
{
for (int i = 0; i < SonList.size(); i++)
{
if (i == Selector && Is_Selected == true && SonList.at(i).SonList.size() != 0)
if (SonList.at(i).Is_Selected == false)
return this;
else
return SonList.at(i).Locate(-1);
}
return this;
}
}
以上为个人经验,希望能给大家一个参考,也希望大家多多支持。
相关文章