此版本已经过多次调试测试,后续大概率不会再进行更新,目前唯一能想到的改进方案是添加项目函数(Append_Item)的最后一个参数(Ids,这个参数用于指定当前添加物品的层级,是一个int类型的数组。例如[0,0]代表该物品为第一层第一个的子列表下的第二层第一个、[1,2]代表该物品为第一层第二个的子列表下的第二层第三个。),这个参数需要在函数外先初始化一个数组再作为入参使用,实际使用中可能需要初始化大量数组。
作为控制台简易界面效果的最后一个版本,此版本摒弃了之前巨量的设置与获取接口,仅向用户提供最基本的添加与显示接口,用户并不需要了解内部的实现原理,防止误用的同时也降低了使用的学习成本。
添加物品的参数 New_Item为此物品的显示名称,Space为选项和标题的空格数 AA-BB-CC AA左空格 BB右空格 CC页面物品限制数量。FunC为选定此物品后执行的函数。Depth为深度,Ids为深度对应的层级,例如[0,0]的Ids对应的就是两层深度[1,2,3,4]对应为四层深度,如深度与层级不一致可能导致未定义错误。
显示物品函数无任何参数,调用后会进入显示绘制的死循环,此项目的按键操作在代码中有详细介绍。
TANXL_CONSOLE_LIST.H VERSION_1_8
//_VERSION_1_8_ UPDATE LOG
// LAST_UPDATE 2023-01-05 16:44
#pragma once
#ifndef _TANXL_CONSOLE_LIST_
#define _TANXL_CONSOLE_LIST_
#include <iostream>
#include <vector>
#include <conio.h>
#include <iomanip>
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)() = nullptr);
const std::string Get_Version();
void Display_Once();
void Append_Item(std::string New_Item, unsigned Space = 0x171109, void(*FunC)() = nullptr, int Depth = 0, int* Ids = nullptr);
private:
void Display(int Depth = 0, unsigned Def_Col = FONT_COLOR_WHITE | BACK_COLOR_RED, unsigned Real_Sel = FONT_COLOR_WHITE | BACK_COLOR_PURPLE);
bool Insert_Action(unsigned* Action_Num, bool* Action_Bol, size_t List_Size);
CONSOLE* Locate(int Target = 0);
std::string _Name;
// _Selector 用于记录当前列表指向的选项序号
unsigned _Selector;
// _Page 用于记录当前指定的页面序号
int _Page;
// _Is_Selected 用于记录当前是否已选定此选项
bool _Is_Selected;
bool _Is_Funcwork;
std::vector<CONSOLE> _SonList;
void (*_Func)();
unsigned _SSpace;// { 0x171109 }选项和标题的空格数 AA-BB-CC AA左空格 BB右空格 CC页面物品限制数量
const std::string _Version{ "1.8" };
};
#endif
TANXL_CONSOLE_LIST.CPP VERSION_1_8
#pragma once
#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 == nullptr)
this->_Is_Funcwork = false;
}
//添加函数
void CONSOLE::Append_Item(std::string New_Item, unsigned Space, void (*FunC)(), int Depth, int* Ids)
{
if (Depth == 0)
this->_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 };
this->_Page = this->_Selector / (_SSpace & 0x00ff);
for (int i = this->_Page * (_SSpace & 0x00ff); (i < _SonList.size()) && (i < (this->_Page + 1) * static_cast<int>(this->_SSpace & 0x00ff)); ++i)
{
for (int j{ Depth }; j > 0; j--)
std::cout << "\t";
if (i == this->_Selector)
Col(Real_Sel);
else
Col(Def_Col);
std::cout << std::setw((this->_SSpace & 0xff0000) >> 16) << this->_SonList.at(i)._Name << std::setw((this->_SSpace & 0x00ff00) >> 8) << " " << std::endl;
Col();
if ((this->_SonList.at(i)._SonList.size() == 0) && (this->_Is_Selected == true) && (this->_Selector == i))//在包含子项目为0时自动退出
{
if (this->_SonList.at(i)._Is_Funcwork)
this->_SonList.at(i)._Func();
this->_Is_Selected = false;
}
if ((this->_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) << 4) + ((Def_Col & 0xf0) >> 4), Real_Sel);
Is_Line_Need = 1;
}
if (!Is_Line_Need)
std::cout << std::endl;
if (Is_Line_Need)
Is_Line_Need = false;
Col();
}
}
const std::string CONSOLE::Get_Version()
{
return this->_Version;
}
void CONSOLE::Display_Once()
{
static bool Insert{ true };
bool Cover{ false };
unsigned* 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);
break;
}
}
bool CONSOLE::Insert_Action(unsigned* Action_Num, bool* Action_Bol, size_t List_Size)
{
char key = _getch();
if ((key == 'c') || (key == 'C'))//如果输入了大小写的C则返回上一级
{
*Action_Bol = false;
return false;
}
if ((key >= 48) && (key <= 57))//判断是否是从零到九的数字
{//(static_cast<int>(key - 48) >= 0) && (static_cast<int>(key - 48) <= 9)
if (key <= List_Size + 48)//如果是,且小于等于选项总数则直接指定这个选项
*Action_Num = key - 49;
else
*Action_Num = static_cast<unsigned>(List_Size) - 1;//如果超出了最大值,则指向最大值
*Action_Bol = true;
}
else if ((key == 'w') || (key == 'W') || (key == 72))//如果输入了大小写的W或者上箭头,则执行MoveUp
*Action_Num = *Action_Num == 0 ? static_cast<unsigned>(List_Size) - 1 : -- * Action_Num;
else if ((key == 's') || (key == 'S') || (key == 80))//如果输入了大小写的S或者下箭头,则执行MoveDown
*Action_Num = *Action_Num == List_Size - 1 ? 0 : ++ * Action_Num;
else if ((key == 'a') || (key == 'A') || (key == 75))//如果输入了大小写的A或者左箭头,则执行向上翻页
*Action_Num = *Action_Num - (this->_SSpace & 0x0000ff) < 0 ? 0 : *Action_Num - (this->_SSpace & 0x0000ff);
else if ((key == 'd') || (key == 'D') || (key == 77))//如果输入了大小写的D或者右箭头,则执行向下翻页
*Action_Num = *Action_Num + (this->_SSpace & 0x0000ff) > static_cast<unsigned>(List_Size) - 1 ? static_cast<unsigned>(List_Size) - 1 : *Action_Num + (this->_SSpace & 0x0000ff);
else if (key == '\r')//回车确认
*Action_Bol = true;
return true;
}
CONSOLE* CONSOLE::Locate(int Target)
{
if (Target == 0)
{
for (int i{ 0 }; i < this->_SonList.size(); ++i)
{
if ((i == this->_Selector) && (this->_Is_Selected == true))
return this->_SonList.at(i).Locate();
}
return this;
}
else
{
for (int i{ 0 }; i < _SonList.size(); ++i)
{
if ((i == this->_Selector) && (this->_Is_Selected == true) && (this->_SonList.at(i)._SonList.size() != 0))
if (this->_SonList.at(i)._Is_Selected == false)
return this;
else
return this->_SonList.at(i).Locate(-1);
}
return this;
}
}
例程同之前的1.5版本。
C++控制台强化实现一定界面效果(简洁版)