C++控制台强化如何实现一定界面效果(简洁版)

目录
  • TANXL_CONSOLE_LIST VERSION_1_4
    • TANXL_CONSOLE_LIST.H VERSION_1_4
  • TANXL_CONSOLE_LIST.H VERSION_1_5
    • TANXL_CONSOLE_LIST.H VERSION_1_5
    • TANXL_CONSOLE_LIST.CPP VERSION_1_5
    • Main.CPP(测试用)
  • TANXL_CONSOLE_LIST.H VERSION_1_5+_Final
  • TANXL_CONSOLE_LIST.H VERSION_1_5++_Final
  • TANXL_CONSOLE_LIST.CPP VERSION_1_5++_Final

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"), /*SonList(NULL),*/ Func(NULL) {};
	Function(std::string N, void(*F)()) :Name(N),/* SonList(NULL),*/ 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;
	}
}

以上为个人经验,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • C++实现基于控制台界面的吃豆子游戏

    本文实例讲述了C++实现基于控制台界面的吃豆子游戏.分享给大家供大家参考.具体分析如下: 程序运行界面如下所示: ESC键可退出游戏. main.cpp源文件如下: #include "lib.h" #pragma once extern int level; int main() { FOOD food; WALL wall; BODY CurPos; HALL hall; int iExit = 0; while(1) { if(iExit) break; Init(&fo

  • C++实现简单的扫雷游戏(控制台版)

    C++新手的代码,请各位多包涵. 用C++写的一个简单的控制台版扫雷游戏.玩家通过输入方块的坐标来翻开方块. 只是一个雏形,能够让玩家执行翻开方块的操作并且判断输赢,还未添加标记方块.游戏菜单.记录游戏时间.重新开一局等等的功能. 玩家输入坐标的方式来翻开方块只适用于小型的"雷区",若"雷区"大了,用坐标会变得很不方便. 代码片段扫雷V1.1 #include<stdio.h> #include<Windows.h> #define YELL

  • C++控制台实现简单注册登录

    C++控制台实现简单的注册登录,供大家参考,具体内容如下 #include<iostream> #include<string> #include <vector> #include <conio.h> void Display();//调用display显示switch()界面 void Register();//注册 void Enter();//登录 using namespace std; class user{ private: string ID

  • C++控制台强化如何实现一定界面效果(简洁版)

    目录 TANXL_CONSOLE_LIST VERSION_1_4 TANXL_CONSOLE_LIST.H VERSION_1_4 TANXL_CONSOLE_LIST.H VERSION_1_5 TANXL_CONSOLE_LIST.H VERSION_1_5 TANXL_CONSOLE_LIST.CPP VERSION_1_5 Main.CPP(测试用) TANXL_CONSOLE_LIST.H VERSION_1_5+_Final TANXL_CONSOLE_LIST.H VERSION

  • Android使用ViewDragHelper实现QQ6.X最新版本侧滑界面效果实例代码

    (一).前言: 这两天QQ进行了重大更新(6.X)尤其在UI风格上面由之前的蓝色换成了白色居多了,侧滑效果也发生了一些变化,那我们今天来模仿实现一个QQ6.X版本的侧滑界面效果.今天我们还是采用神器ViewDragHelper来实现. 本次实例具体代码已经上传到下面的项目中,欢迎各位去star和fork一下. https://github.com/jiangqqlmj/DragHelper4QQ FastDev4Android框架项目地址:https://github.com/jiangqqlm

  • Android仿拉手网团购App产品详情界面效果

    先给大家展示下效果图,如果感觉还不错,请参考实例代码. 效果图如下所示: 具体代码如下所示: activity_detail.xml <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.an

  • Android界面效果UI开发资料汇总(附资料包)

    简介: Android界面效果UI开发资料汇总 1. Android_UI开发专题.rar 2. android界面效果全汇总.rar 对于Android平台的资源类android.content.res.Resources可能很多网友比较陌生,一起来看看SDK上是怎么介绍的吧,Contains classes for accessing application resources, such as raw asset files, colors, drawables, media or oth

  • Android利用ViewPager实现用户引导界面效果的方法

    本文实例讲述了Android利用ViewPager实现用户引导界面效果.分享给大家供大家参考,具体如下: 我相信有很多朋友在装完软件首次打开时,有很多软件都有一个软件功能介绍, 例如刚装完微信打开它,有很多介绍微信功能的图片,并且在屏幕下方有很多小圆点提示你当前图片的位置. 今天我就来实现这么个功能 所实现的功能: 1.可以左右滑动功能图片. 2.图片的索引 看出当前图片所在的位置. 3.可循环滑动. 4.图片的索引带有动画效果. 本次学习主要是利用ViewPager实现用户引导界面 在这里,我

  • 使用 electron 实现类似新版 QQ 的登录界面效果(阴影、背景动画、窗体3D翻转)

    现在什么都讲究追赶潮流,觉得 QQ 登录窗口做的效果不错,既然刚学习 electron ,那么就用 electron 模仿一下.其实主要用到的就是 CSS3 的效果:边框圆角.阴影,3D变换.对,就这么简单.先上效果: 下面是关键代码: app.js 'use strict'; const { app, BrowserWindow } = require('electron') const path = require('path') const url = require('url') //

  • Android基于ViewDragHelper仿QQ5.0侧滑界面效果

    QQ5.0侧滑效果实现方案有很多方式,今天我们使用ViewDragHelper来实现一下. 先上效果图: ①自定义控件SlidingMenu继承FrameLayout,放在FrameLayout上面的布局一层叠着者一层,通过getChildAt()可以很方便的获取到任意一层,进而控制此布局的变化. public class SlidingMenu extends FrameLayout { private ViewDragHelper mViewDragHelper; private int m

  • Java Swing仿QQ登录界面效果

    本文实例为大家分享了Java Swing仿QQ登录界面展示的具体代码,供大家参考,具体内容如下 闲来无事将早些时候已实现的QQ登录界面再实现了一遍,纯手工打造(意思是没有用NetBeans.MyEclipse的拖动功能). 源代码如下: package ibees.qq; import java.awt.BorderLayout; import java.net.URL; import javax.swing.ImageIcon; import javax.swing.JButton; impo

  • Unity实现滑动更换界面效果

    在做2048这个游戏时,因为菜单页面还能查看游戏规则,而这些规则又不在同一个页上,所以需要滑动页面实现页面切换,但是仅仅使用unity提供的组件做出的效果仅有一个切换的意思,交互感很差,所以在组件的基础上又写了一个控制页面切换的类.而界面切换就是实现一个滚动的视图. 在unity编辑器中实现滚动视图的基本操作:需要用Scroll Rect组件 首先可以看看官方用户手册中关于Scroll Rect组件的讲解,说的很明白.最精辟的描述就是用于使子 RectTransform 滚动的组件. 滚动视图中

  • js遮罩效果制作弹出注册界面效果

    本文实例为大家分享了js遮罩效果弹出界面的具体代码,供大家参考,具体内容如下 <head> <meta charset="UTF-8"> <title>遮罩</title> <style> * { margin: 0; padding: 0; } #shade{ position: fixed; width: 100%; height: 100%; display: none; } .shade-background{ wid

随机推荐