Windows C++控制台菜单库
- 声明:
- 演示视频:
- 一、前言
- 二、具体框架
- 三、源码展示
- console_screen_set.h
- frame
- console_screen_frame_base.h
- console_screen_frame_char.h
- console_screen_frame_wchar_t.h
- console_screen_frame.h
- menu
- console_screen_menu_base.h
- console_screen_menu_operate.h
- console_screen_menu.h
- text
- console_screen_text_base.h
- console_screen_text.h
- 四、代码参考
声明:
开发环境为 VS2022 C++,菜单库源码(2200行左右)为本人独立制作,转载使用请标明出处,谢谢!
演示视频:
C++菜单库例子展示
一、前言
做控制台菜单的时候总感觉太耗时了,因为坐标不对需要修改,还要一个一个检查,以及颜色的处理。
具体操作可看这篇博客C语言伪图形与键盘操作加扫雷实例(写的太挫了),所以我想制作一个控制台菜单库,便于在菜单方面的快速开发。
二、具体框架
因为制作的时候是走一步看一步,导致设计十分冗余,后续有时间可能会更新调整。这里我列举一些里面的功能:
- set 包含常用的函数,例如光标移动、隐藏等等。
- menu(模板) 包含选项、框架、内置键盘操作、内置鼠标操作、打印、清除等等。
- text(模板) 包含打印、清除等等。
在使用宽字符(wchar_t)对应的类,如:wmenu、wtext、应该加上这一句:
std::wcout.imbue(std::locale("zh_CN"));
详细可参考 C++基础(十八)区域设置、locale、中文乱码、中文不输出 ,这里不赘述。
三、源码展示
console_screen_set.h
#pragma once#include <CoreWindow.h>
#include <stdio.h>namespace my
{inline void SetPos(int x, int y){COORD pos = { x, y };SetConsoleCursorPosition(GetStdHandle(STD_OUTPUT_HANDLE), pos);}inline void HideCursor(){CONSOLE_CURSOR_INFO cursor_info = { 1, 0 };SetConsoleCursorInfo(GetStdHandle(STD_OUTPUT_HANDLE), &cursor_info);}inline void SetWordSize(int SizeX, int SizeY){CONSOLE_FONT_INFOEX font_infoex;COORD pos = { SizeX, SizeY };font_infoex.cbSize = sizeof(CONSOLE_FONT_INFOEX);font_infoex.dwFontSize = pos;SetCurrentConsoleFontEx(GetStdHandle(STD_OUTPUT_HANDLE), false, &font_infoex);}inline void FlushBuffer(){FlushConsoleInputBuffer(GetStdHandle(STD_INPUT_HANDLE));}inline void SetScreenSize(short consoleWide, short consoleHigh){char cmd[100];sprintf_s(cmd, "mode con cols=%d lines=%d", consoleWide, consoleHigh);system(cmd);}inline void GetMouseOperate(){if (!SetConsoleMode(GetStdHandle(STD_INPUT_HANDLE), ENABLE_EXTENDED_FLAGS | ENABLE_WINDOW_INPUT | ENABLE_MOUSE_INPUT)){fprintf(stderr, "%s\n", "SetConsoleMode");}}
}
frame
console_screen_frame_base.h
#pragma once#include <CoreWindow.h>
#include <cassert>namespace my
{template<class T>class console_screen_frame_base{template<class Type, class CH, class STRING>friend class console_screen_frame;template<class PFUNC, class MENU, class FRAME, class CHAR, class STRING>friend class console_screen_menu;template<class TEXTCHAR, class FRAME, class STRING, class CHAR>friend class console_screen_text;public:console_screen_frame_base(int x = 0, int y = 0, int high = 5, int wide = 10,T up = 0, T down = 0, T left = 0, T right = 0,T top_left = 0, T bottom_left = 0, T top_right = 0, T bottom_right = 0):_x(x), _y(y), _high(high), _wide(wide), _up(up), _down(down), _left(left), _right(right), _top_left(top_left), _bottom_left(bottom_left), _top_right(top_right), _bottom_right(bottom_right){assert(x >= 0 && y >= 0);assert(high >= 0 && wide >= 0);}void changePos(int x, int y){assert(x >= 0 && y >= 0);_x = x;_y = y;}void changeFrameSize(int high, int wide){assert(high >= 0 && wide >= 0);_high = high;_wide = wide;}void changeSide(T up = 0, T down = 0, T left = 0, T right = 0){_up = up == 0 ? _up : up;_down = down == 0 ? _down : down;_left = left == 0 ? _left : left;_right = right == 0 ? _right : right;}void changeCorner(T top_left = 0, T bottom_left = 0, T top_right = 0, T bottom_right = 0){_top_left = top_left == 0 ? _top_left : top_left;_bottom_left = bottom_left == 0 ? _bottom_left : bottom_left;_top_right = top_right == 0 ? _top_right : top_right;_bottom_right = bottom_right == 0 ? _bottom_right : bottom_right;}void changeUp(T up){_up = up;}void changeDown(T down){_down = down;}void changeLeft(T left){_left = left;}void changeRight(T right){_right = right;}void changeTopLeft(T top_left){_top_left = top_left;}void changeTopRight(T top_right){_top_right = top_right;}void changeBottomLeft(T bottom_left){_bottom_left = bottom_left;}void changeBottomRight(T bottom_right){_bottom_right = bottom_right;}protected:void printFrame(){if (_up != 0){printCharUp();}if (_down != 0){printCharDown();}if (_left != 0){printCharLeft();}if (_right != 0){printCharRight();}if (_top_left != 0 ||_top_right != 0 ||_bottom_left != 0 ||_bottom_right != 0){printCharCorner();}}virtual void printCharUp() = 0;virtual void printCharDown() = 0;virtual void printCharLeft() = 0;virtual void printCharRight() = 0;virtual void printCharCorner() = 0;void cleanFrame(){if (_up != 0){cleanCharUp();}if (_down != 0){cleanCharDown();}if (_left != 0){cleanCharLeft();}if (_right != 0){cleanCharRight();}if (_top_left != 0 ||_top_right != 0 ||_bottom_left != 0 ||_bottom_right != 0){cleanCharCorner();}}virtual void cleanCharUp() = 0;virtual void cleanCharDown() = 0;virtual void cleanCharLeft() = 0;virtual void cleanCharRight() = 0;virtual void cleanCharCorner() = 0;protected:short _x;short _y;short _high;short _wide;T _up;T _down;T _left;T _right;T _top_left = 0;T _bottom_left = 0;T _top_right = 0;T _bottom_right = 0;};
}
console_screen_frame_char.h
#pragma once#include "console_screen_frame_base.h"
#include "console_screen_set.h"
#include <iostream>namespace my
{extern void SetPos(int x, int y);class console_screen_frame_char : public console_screen_frame_base<signed char>{public:console_screen_frame_char(int x, int y, int high, int wide,signed char up = 0, signed char down = 0,signed char left = 0, signed char right = 0,signed char top_left = 0, signed char bottom_left = 0,signed char top_right = 0, signed char bottom_right = 0):console_screen_frame_base(x, y, high, wide, up, down, left, right,top_left, bottom_left, top_right, bottom_right){;}void show(){printFrame();}void clean(){cleanFrame();}protected:void printCharUp(){SetPos(_x + 1, _y);for (int wide = 1; wide <= _wide - 2; ++wide){std::cout << _up;}}void printCharDown(){SetPos(_x + 1, _y + _high - 1);for (int wide = 1; wide <= _wide - 2; ++wide){std::cout << _down;}}void printCharLeft(){for (int high = 1; high <= _high - 2; ++high){SetPos(_x, _y + high);std::cout << _left;}}void printCharRight(){for (int high = 1; high <= _high - 2; ++high){SetPos(_x + _wide - 1, _y + high);std::cout << _right;}}void printCharCorner(){SetPos(_x, _y);std::cout << _top_left;SetPos(_x + _wide - 1, _y);std::cout << _top_right;SetPos(_x, _y + _high - 1);std::cout << _bottom_left;SetPos(_x + _wide - 1, _y + _high - 1);std::cout << _bottom_right;}void cleanCharUp(){signed char temp = _up;_up = ' ';printCharUp();_up = temp;}void cleanCharDown(){signed char temp = _down;_down = ' ';printCharDown();_down = temp;}void cleanCharLeft(){signed char temp = _left;_left = ' ';printCharLeft();_left = temp;}void cleanCharRight(){signed char temp = _right;_right = ' ';printCharRight();_right = temp;}void cleanCharCorner(){signed char temp1 = _top_left;signed char temp2 = _bottom_left;signed char temp3 = _top_right;signed char temp4 = _bottom_right;changeCorner(' ', ' ', ' ', ' ');printCharCorner();changeCorner(temp1, temp2, temp3, temp4);}};
}
console_screen_frame_wchar_t.h
#pragma once#include "console_screen_frame_base.h"
#include "console_screen_set.h"
#include <iostream>namespace my
{class console_screen_frame_wchar_t : public console_screen_frame_base<wchar_t>{public:console_screen_frame_wchar_t(int x, int y, int high, int wide,wchar_t up = 0, wchar_t down = 0,wchar_t left = 0, wchar_t right = 0,wchar_t top_left = 0, wchar_t bottom_left = 0,wchar_t top_right = 0, wchar_t bottom_right = 0):console_screen_frame_base(x, y, high, wide, up, down, left, right,top_left, bottom_left, top_right, bottom_right){;}void show(){printFrame();}void clean(){cleanFrame();}protected:void printCharUp(){for (int wide = 0; wide <= _wide - 6; wide += 2){SetPos(_x + 2 + wide, _y);std::wcout << _up;}}void printCharDown(){for (int wide = 0; wide <= _wide - 6; wide += 2){SetPos(_x + 2 + wide, _y + _high - 1);std::wcout << _down;}}void printCharLeft(){for (int high = 1; high <= _high - 2; ++high){SetPos(_x, _y + high);std::wcout << _left;}}void printCharRight(){for (int high = 1; high <= _high - 2; ++high){SetPos(_x + _wide - 2, _y + high);std::wcout << _right;}}void printCharCorner(){SetPos(_x, _y);std::wcout << _top_left;SetPos(_x + _wide - 2, _y);std::wcout << _top_right;SetPos(_x, _y + _high - 1);std::wcout << _bottom_left;SetPos(_x + _wide - 2, _y + _high - 1);std::wcout << _bottom_right;}void cleanCharUp(){SetPos(_x + 2, _y);for (int wide = 0; wide <= _wide - 4; ++wide){std::cout << ' ';}}void cleanCharDown(){SetPos(_x + 2, _y + _high - 1);for (int wide = 0; wide <= _wide - 4; ++wide){std::cout << ' ';}}void cleanCharLeft(){for (int high = 1; high <= _high - 2; ++high){SetPos(_x, _y + high);std::cout << ' ' << ' ';}}void cleanCharRight(){for (int high = 1; high <= _high - 2; ++high){SetPos(_x + _wide - 2, _y + high);std::cout << ' ' << ' ';}}void cleanCharCorner(){SetPos(_x, _y);std::cout << ' ' << ' ';SetPos(_x + _wide - 2, _y);std::cout << ' ' << ' ';SetPos(_x, _y + _high - 1);std::cout << ' ' << ' ';SetPos(_x + _wide - 2, _y + _high - 1);std::cout << ' ' << ' ';}};
}
console_screen_frame.h
#pragma once#include "console_screen_frame_char.h"
#include "console_screen_frame_wchar_t.h"
#include <vector>
#include <utility>namespace my
{enum FRAME_DIRECTION{Up = 0,Down,Left,Right};template<class T, class CH, class STRING>class console_screen_frame{template<class PFUNC, class MENU, class FRAME, class CHAR, class STRING>friend class console_screen_menu;template<class TEXTCHAR, class FRAME, class STRING, class CHAR>friend class console_screen_text;public:console_screen_frame(int x, int y, int high, int wide,CH up = 0, CH down = 0, CH left = 0, CH right = 0,CH top_left = 0, CH bottom_left = 0, CH top_right = 0, CH bottom_right = 0):_the_char(x, y, high, wide, up, down, left, right, top_left, bottom_left, top_right, bottom_right){;}void setPos(int x, int y){_the_char.changePos(x, y);}void setFrameSize(int high, int wide){_the_char.changeFrameSize(high, wide);}void setSide(CH up = 0, CH down = 0, CH left = 0, CH right = 0){_the_char.changeSide(up, down, left, right);}void setCorner(CH top_left = 0, CH bottom_left = 0,CH top_right = 0, CH bottom_right = 0){_the_char.changeCorner(top_left, bottom_left, top_right, bottom_right);}void setUp(CH up){_the_char.changeUp(up);}void setDown(CH down){_the_char.changeDown(down);}void setLeft(CH left){_the_char.changeLeft(left);}void setRight(CH right){_the_char.changeRight(right);}void setTopLeft(CH top_left){_the_char.changeTopLeft(top_left);}void setTopRight(CH top_right){_the_char.changeTopRight(top_right);}void setBottomLeft(CH bottom_left){_the_char.changeBottomLeft(bottom_left);}void setBottomRight(CH bottom_right){_the_char.changeBottomRight(bottom_right);}void frameShow(){_the_char.show();if (sizeof(CH) == sizeof(signed char)){wordShow((void(*)(STRING))&getCout, (void(*)(CH))&getCoutC);}else{wordShow((void(*)(STRING))&getWcout, (void(*)(CH))&getWcoutC);}}void frameClean(){_the_char.clean();}void numWord(int number){_word.resize(number);_word_space.resize(number);}void setWord(int pos, STRING str1, signed char direction, short distance){assert(pos >= 0 && pos < _word.size());_word[pos] = str1;_word_space[pos] = { direction, distance };}void recallWord(int pos){assert(pos >= 0 && pos < _word.size());_word.erase(_word.begin() + pos);_word_space.erase(_word_space.begin() + pos);}protected:void wordShow(void(*outfuncString)(STRING), void(*outfuncChar)(CH)){for (int i = 0; i < _word.size(); ++i){if (_the_char._up != 0 && _word_space[i].first == Up){SetPos(_the_char._x + _word_space[i].second, _the_char._y);if (_word[i] == nullptr){continue;}outfuncString(_word[i]);}else if (_the_char._down != 0 && _word_space[i].first == Down){SetPos(_the_char._x + _word_space[i].second, _the_char._y + _the_char._high - 1);if (_word[i] == nullptr){continue;}outfuncString(_word[i]);}else if (_the_char._left != 0 && _word_space[i].first == Left){int len = clen(_word[i]);for (int j = 0; j < len; ++j){SetPos(_the_char._x, _the_char._y + _word_space[i].second + j);if (_word[i] == nullptr){continue;}outfuncChar(_word[i][j]);}}else if (_the_char._right != 0 && _word_space[i].first == Right){int len = clen(_word[i]);for (int j = 0; j < len; ++j){SetPos(_the_char._x + _the_char._wide - sizeof(CH), _the_char._y + _word_space[i].second + j);if (_word[i] == nullptr){continue;}outfuncChar(_word[i][j]);}}}}static void getWcout(STRING str1){std::wcout << str1;}static void getCout(STRING str1){std::cout << str1;}static void getWcoutC(CH ch){std::wcout << ch;}static void getCoutC(CH ch){std::cout << ch;}protected:std::vector<STRING> _word; // 嵌入词std::vector<std::pair<signed char, short>> _word_space; // 嵌入词位置T _the_char;typedef size_t(*p_T_char)(STRING);p_T_char clen = sizeof(CH) == sizeof(signed char) ? (p_T_char)&strlen : (p_T_char)&wcslen;};typedef console_screen_frame<console_screen_frame_char, signed char, const char*> frame;typedef console_screen_frame<console_screen_frame_wchar_t, wchar_t, const wchar_t*> wframe;}
menu
console_screen_menu_base.h
#pragma once#include "console_screen_set.h"
#include <iostream>
#include <string>
#include <vector>
#include <cassert>
#include <Windows.h>
#include <utility>namespace my
{template<class T>static T Max(T a, T b){return a > b ? a : b;}typedef enum CONSOLE_SCREEN_COLOR{CBlack = 0,CBlue,CGreen,CLight_blue,CRed,CPurple,CYellow,CWhite,BBlack = 0,BBlue = 0x10,BGreen = 0x20,BLight_blue = 0x30,BRed = 0x40,BPurple = 0x50,BYellow = 0x60,BWhite = 0x70} the_color;class console_screen_menu_base{public:console_screen_menu_base(int x, int y, int rowNum = 1, int colNum = 1, int high = 1, int wide = 1):_x(x), _y(y), _high(high), _wide(wide), _rowNum(rowNum), _colNum(colNum), _option(rowNum, std::vector<std::string>(colNum, std::string("nullptr"))), _char_space(rowNum, std::vector<std::pair<short, short>>(colNum, { 1, 1 })), _char_color(rowNum, std::vector<std::pair<short, bool>>(colNum, { CWhite, 0 })), _background_space(rowNum, std::vector<std::pair<short, short>>(colNum, { 0, 0 })), _background_color(rowNum, std::vector<std::pair<short, bool>>(colNum, { BBlack, 0 })){assert(rowNum >= 1 && colNum >= 1);assert(x >= 0 && y >= 0);assert(high >= 0 && wide >= 0);}const std::string& getOption(int rowPos, int colPos){assert(rowPos >= 1 && colPos >= 1);return _option[rowPos - 1][colPos - 1];}void setOption(int rowPos, int colPos, const std::string& str1,short front = 1, short back = 1){assert(rowPos >= 1 && colPos >= 1);assert(front >= 0 && back >= 0);assert(rowPos <= _rowNum && colPos <= _colNum);_option[rowPos - 1][colPos - 1] = str1;_char_space[rowPos - 1][colPos - 1] = { front, back };}void setColor(int rowPos, int colPos, int charColor, bool charStrength, int backgroundColor = 0, bool backgroundStrength = false){char_color(rowPos, colPos, charColor, charStrength);background_color(rowPos, colPos, backgroundColor, backgroundStrength);}void setCharColor(int rowPos, int colPos, int colorNum, bool strength = false){char_color(rowPos, colPos, colorNum, strength);}void setBackgroundColor(int rowPos, int colPos, int colorNum, bool strength = false){background_color(rowPos, colPos, colorNum, strength);}void setCharSpace(int rowPos, int colPos, int front, int back){assert(rowPos >= 1 && colPos >= 1);_char_space[rowPos - 1][colPos - 1] = { front, back };}void setBackgroundSpace(int rowPos, int colPos, int front, int back){assert(rowPos >= 1 && colPos >= 1);_background_space[rowPos - 1][colPos - 1] = { front, back };}void setRowSpace(int row){assert(row >= 0);_row_space = row;}void setPos(int x, int y){assert(x >= 0 && y >= 0);_x = x;_y = y;}void show(){show_or_clean_ready(true);}void clean(){show_or_clean_ready(false);}protected:void char_color(int rowPos, int colPos, int colorNum, bool strength){assert(CBlack <= colorNum && colorNum <= CWhite);_char_color[rowPos - 1][colPos - 1] = { colorNum, strength };}void background_color(int rowPos, int colPos, int colorNum, bool strength){assert(BBlack <= colorNum && colorNum <= BWhite);_background_color[rowPos - 1][colPos - 1] = { colorNum, strength };}void clean_ready(int i, int j, int x, int y){int len1 = _option[i][j].size();if (_background_space[i][j].first > 0){len1 += _background_space[i][j].first;}if (_background_space[i][j].second > 0){len1 += _background_space[i][j].second;}// 补丁:正序打印会影响宽字体,逆向可解决for (int i = len1 - 1; i >= 0; --i){SetPos(x + i, y);std::cout << ' ';}}void show_ready(int i, int j){int charStrength = 0;int backgroundStrength = 0;if (_background_color[i][j].second == true){backgroundStrength = BACKGROUND_INTENSITY;}if (_char_color[i][j].second == true){charStrength = FOREGROUND_INTENSITY;}if (_background_space[i][j].first > 0){SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), _background_color[i][j].first | backgroundStrength);std::cout << std::string(_background_space[i][j].first, ' ');}SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), _char_color[i][j].first | charStrength | _background_color[i][j].first | backgroundStrength);std::cout << _option[i][j];if (_background_space[i][j].second > 0){SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), _background_color[i][j].first | backgroundStrength);std::cout << std::string(_background_space[i][j].second, ' ');}SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), CWhite | BBlack);}void show_or_clean_ready(bool option){int countPosY = 0;for (int i = 0; i < _rowNum; ++i){if (i != 0){countPosY += _row_space;}int countPosX = 0;for (int j = 0; j < _colNum; ++j){int front = _char_space[i][j].first;if (j != 0){countPosX += _option[i][j - 1].size();countPosX += _char_space[i][j - 1].first + _background_space[i][j - 1].first;countPosX += _background_space[i][j - 1].second + _char_space[i][j - 1].second;}SetPos(_x + front + countPosX, _y + i + countPosY);if (option == true){show_ready(i, j);}else{clean_ready(i, j, _x + front + countPosX, _y + i + countPosY);}}}}protected:std::vector<std::vector<std::string>> _option; // 选项//std::vector<std::vector<const char*>> _option;std::vector<std::vector<std::pair<short, short>>> _char_space; // 字符间距std::vector<std::vector<std::pair<short, bool>>> _char_color; // 字符 颜色 与 颜色加强std::vector<std::vector<std::pair<short, short>>> _background_space; // 背景间距std::vector<std::vector<std::pair<short, bool>>> _background_color; // 背景 颜色 与 颜色加强short _x;short _y;short _high;short _wide;//short _rowNum = 1;//short _colNum = 1;int _rowNum = 1;int _colNum = 1;signed char _row_space = 0; // 行距};
}
console_screen_menu_operate.h
#pragma once#include "console_screen_set.h"
#include <iostream>
#include <string>
#include <vector>
#include <cassert>
#include <Windows.h>
#include <utility>namespace my
{template<class T>static T Max(T a, T b){return a > b ? a : b;}typedef enum CONSOLE_SCREEN_COLOR{CBlack = 0,CBlue,CGreen,CLight_blue,CRed,CPurple,CYellow,CWhite,BBlack = 0,BBlue = 0x10,BGreen = 0x20,BLight_blue = 0x30,BRed = 0x40,BPurple = 0x50,BYellow = 0x60,BWhite = 0x70} the_color;class console_screen_menu_base{public:console_screen_menu_base(int x, int y, int rowNum = 1, int colNum = 1, int high = 1, int wide = 1):_x(x), _y(y), _high(high), _wide(wide), _rowNum(rowNum), _colNum(colNum), _option(rowNum, std::vector<std::string>(colNum, std::string("nullptr"))), _char_space(rowNum, std::vector<std::pair<short, short>>(colNum, { 1, 1 })), _char_color(rowNum, std::vector<std::pair<short, bool>>(colNum, { CWhite, 0 })), _background_space(rowNum, std::vector<std::pair<short, short>>(colNum, { 0, 0 })), _background_color(rowNum, std::vector<std::pair<short, bool>>(colNum, { BBlack, 0 })){assert(rowNum >= 1 && colNum >= 1);assert(x >= 0 && y >= 0);assert(high >= 0 && wide >= 0);}const std::string& getOption(int rowPos, int colPos){assert(rowPos >= 1 && colPos >= 1);return _option[rowPos - 1][colPos - 1];}void setOption(int rowPos, int colPos, const std::string& str1,short front = 1, short back = 1){assert(rowPos >= 1 && colPos >= 1);assert(front >= 0 && back >= 0);assert(rowPos <= _rowNum && colPos <= _colNum);_option[rowPos - 1][colPos - 1] = str1;_char_space[rowPos - 1][colPos - 1] = { front, back };}void setColor(int rowPos, int colPos, int charColor, bool charStrength, int backgroundColor = 0, bool backgroundStrength = false){char_color(rowPos, colPos, charColor, charStrength);background_color(rowPos, colPos, backgroundColor, backgroundStrength);}void setCharColor(int rowPos, int colPos, int colorNum, bool strength = false){char_color(rowPos, colPos, colorNum, strength);}void setBackgroundColor(int rowPos, int colPos, int colorNum, bool strength = false){background_color(rowPos, colPos, colorNum, strength);}void setCharSpace(int rowPos, int colPos, int front, int back){assert(rowPos >= 1 && colPos >= 1);_char_space[rowPos - 1][colPos - 1] = { front, back };}void setBackgroundSpace(int rowPos, int colPos, int front, int back){assert(rowPos >= 1 && colPos >= 1);_background_space[rowPos - 1][colPos - 1] = { front, back };}void setRowSpace(int row){assert(row >= 0);_row_space = row;}void setPos(int x, int y){assert(x >= 0 && y >= 0);_x = x;_y = y;}void show(){show_or_clean_ready(true);}void clean(){show_or_clean_ready(false);}protected:void char_color(int rowPos, int colPos, int colorNum, bool strength){assert(CBlack <= colorNum && colorNum <= CWhite);_char_color[rowPos - 1][colPos - 1] = { colorNum, strength };}void background_color(int rowPos, int colPos, int colorNum, bool strength){assert(BBlack <= colorNum && colorNum <= BWhite);_background_color[rowPos - 1][colPos - 1] = { colorNum, strength };}void clean_ready(int i, int j, int x, int y){int len1 = _option[i][j].size();if (_background_space[i][j].first > 0){len1 += _background_space[i][j].first;}if (_background_space[i][j].second > 0){len1 += _background_space[i][j].second;}// 补丁:正序打印会影响宽字体,逆向可解决for (int i = len1 - 1; i >= 0; --i){SetPos(x + i, y);std::cout << ' ';}}void show_ready(int i, int j){int charStrength = 0;int backgroundStrength = 0;if (_background_color[i][j].second == true){backgroundStrength = BACKGROUND_INTENSITY;}if (_char_color[i][j].second == true){charStrength = FOREGROUND_INTENSITY;}if (_background_space[i][j].first > 0){SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), _background_color[i][j].first | backgroundStrength);std::cout << std::string(_background_space[i][j].first, ' ');}SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), _char_color[i][j].first | charStrength | _background_color[i][j].first | backgroundStrength);std::cout << _option[i][j];if (_background_space[i][j].second > 0){SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), _background_color[i][j].first | backgroundStrength);std::cout << std::string(_background_space[i][j].second, ' ');}SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), CWhite | BBlack);}void show_or_clean_ready(bool option){int countPosY = 0;for (int i = 0; i < _rowNum; ++i){if (i != 0){countPosY += _row_space;}int countPosX = 0;for (int j = 0; j < _colNum; ++j){int front = _char_space[i][j].first;if (j != 0){countPosX += _option[i][j - 1].size();countPosX += _char_space[i][j - 1].first + _background_space[i][j - 1].first;countPosX += _background_space[i][j - 1].second + _char_space[i][j - 1].second;}SetPos(_x + front + countPosX, _y + i + countPosY);if (option == true){show_ready(i, j);}else{clean_ready(i, j, _x + front + countPosX, _y + i + countPosY);}}}}protected:std::vector<std::vector<std::string>> _option; // 选项//std::vector<std::vector<const char*>> _option;std::vector<std::vector<std::pair<short, short>>> _char_space; // 字符间距std::vector<std::vector<std::pair<short, bool>>> _char_color; // 字符 颜色 与 颜色加强std::vector<std::vector<std::pair<short, short>>> _background_space; // 背景间距std::vector<std::vector<std::pair<short, bool>>> _background_color; // 背景 颜色 与 颜色加强short _x;short _y;short _high;short _wide;//short _rowNum = 1;//short _colNum = 1;int _rowNum = 1;int _colNum = 1;signed char _row_space = 0; // 行距};
}
console_screen_menu.h
#pragma once#include "console_screen_frame.h"
#include "console_screen_menu_operate.h"namespace my
{typedef enum console_screen_menu_operate_way{keyboard = 1,mouse,} way;template<class PFUNC = int(*)(),class MENU = console_screen_menu_operate<PFUNC>, class FRAME = frame, class CHAR = signed char, class STRING = const char*>class console_screen_menu{public:console_screen_menu(int x = 0, int y = 0, int high = 10, int wide = 20, int rowNum = 1, int colNum = 1, bool operate_switch = false):_frame(x, y, high, wide),_menu(x, y, operate_switch, rowNum, colNum, high, wide){;}public: // 自定义操作准备template<class T1, class T2, class T3, class T4>int operateCustom(int (*customize)(T1&, T2&, T3&, T4&), T2& fun1, T3& fun2, T4& fun3){return customize(*this, fun1, fun2, fun3);}template<class T1, class T2, class T3>int operateCustom(int (*customize)(T1&, T2&, T3&), T2& fun1, T3& fun2){return customize(*this, fun1, fun2);}template<class T1, class T2>int operateCustom(int (*customize)(T1&, T2&), T2& fun1){return customize(*this, fun1);}template<class T>int operateCustom(int (*customize)(T&)){return customize(*this);}void customSetMenuCharColor(int rowPos, int colPos, int colorNum, bool strength = false){_menu.setCharColor(rowPos, colPos, colorNum, strength);}const std::string& customGetMenuOption(int rowPos, int colPos){return _menu.getOption(rowPos, colPos);}void customSetMenuOption(int rowPos, int colPos, const std::string& str1, short front = 0, short back = 0){setMenuOption(rowPos, colPos, str1, front, back);}void customMouseAndOptionAc(int posX, int posY){_menu.mouseAndOptionAc(posX, posY);}THE_POS customGetMouseCheckAlgorithm(int mouseX, int mouseY){return _menu.mouseAndOptionDockingAlgorithm(mouseX, mouseY);}void customGetMouseOperate(){_menu.getMouseOperate();}void customOperateClean(){_menu.operateClean();}int customGetSleepTime(){return _menu._sleep_time;}PFUNC customGetOptionButton(int cursorX, int cursorY){assert(cursorX >= 0 && cursorX < _menu._colNum);assert(cursorY >= 0 && cursorY < _menu._rowNum);return _menu._the_way[cursorY][cursorX];}int customGetCursorColNum(){return _menu._colNum;}int customGetCursorX(){return _menu._cursorPosX;}void customSetCursorX(int cursorX){_menu.cursorXReset(cursorX);}int customGetCursorRowNum(){return _menu._rowNum;}int customGetCursorY(){return _menu._cursorPosY;}//short customGetOptionRowNum()//{// return _menu._rowNum;//}//short customGetOptionY()//{// return _menu._cursorPosY;//}void customSetCursorY(int cursorY){_menu.cursorYReset(cursorY);}void customSetCursorPos(int cursorX, int cursorY){_menu.cursorReset(cursorX, cursorY);}void customOperateShow(){_menu.operateShow();}bool customMenuCheckOperate(){return _menu._open_operate;}public: // 静态准备void staticInit(bool yes = true){_staticInit = yes;}bool alreadyStaticInit(){return _staticInit;}public: // 有关菜单与框架void setPosCompare(short x, short y){assert(x >= 0);assert(y >= 0);_compare_x = x;_compare_y = y;_menu.setPos(_menu._x + x, _menu._y + y);}void setAndCheckPos(int x, int y){_frame.setPos(x, y);_menu.setPos(x, y);checkPosFrameWithMenu();}void show(){_menu.show();_frame.frameShow();}void clean(){_menu.clean();_frame.frameClean();}public: // 只关于菜单的void setMaxSpaceOper(){_menu.setMaxSpaceOper();}void setSameSpaceOperWithBack(){_menu.setSameSpaceOperWithBack();}void setMenuButton(int rowPos, int colPos, PFUNC customize){_menu.setWay(rowPos, colPos, customize);}void setOperateSpace(int rowPos, int colPos, int front, int back){_menu.setOperateSapce(rowPos, colPos, front, back);}void setOperateColor(int rowPos, int colPos, int colorNum, bool strength = false){_menu.setOperateColor(rowPos, colPos, colorNum, strength);}void operateMode(bool Yes = false){_menu.operateMode(Yes);}int operateWay(int way, int optionX = 1, int optionY = 1){int info = 0;if (way == keyboard){info = _menu.operateKeyboardStart(optionX, optionY);}else if (way == mouse){info = _menu.operateMouseStart();}return info;}//void operateMouseStart()//{// _menu.operateMouseStart();//}//void operateKeyboardStart(int posX = 0, int posY = 0)//{// _menu.operateKeyboardStart(posX, posY);//}void setMenuRowSpace(int row){_menu.setRowSpace(row);}void setMenuBackgroundSpace(int rowPos, int colPos, int front, int back){_menu.setBackgroundSpace(rowPos, colPos, front, back);}void setMenuCharSpace(int rowPos, int colPos, int front, int back){_menu.setCharSpace(rowPos, colPos, front, back);}void setMenuBackgroundColor(int rowPos, int colPos, int colorNum, int strength = false){_menu.setBackgroundColor(rowPos, colPos, colorNum, strength);}void setMenuCharColor(int rowPos, int colPos, int colorNum, int strength = false){_menu.setCharColor(rowPos, colPos, colorNum, strength);}void setMenuColor(int rowPos, int colPos, int charColor, bool charStrength, int backgroundColor = 0, bool backgroundStrength = false){_menu.setColor(rowPos, colPos, charColor, charStrength, backgroundColor, backgroundStrength);}void setMenuOption(int rowPos, int colPos, const std::string& str1, short front = 1, short back = 1){_menu.setOption(rowPos, colPos, str1, front, back);}public: // 只关于框架的void setFrameSide(CHAR up, CHAR down, CHAR left , CHAR right){_frame.setSide(up, down, left, right);checkPosFrameWithMenu();}void setFrameCorner(CHAR top_left, CHAR bottom_left, CHAR top_right, CHAR bottom_right){_frame.setCorner(top_left, bottom_left, top_right, bottom_right);checkPosFrameWithMenu();}void setFrameNumWord(int number){_frame.numWord(number);}void setFrameWord(int pos, STRING str1, signed char direction, short distance){_frame.setWord(pos, str1, direction, distance);}void setFrameRecallWord(int pos){_frame.recallWord(pos);}protected:void checkPosFrameWithMenu(){if (_frame._the_char._x != _menu._x && _frame._the_char._y != _menu._y){return;}short up = 0;short down = 0;short left = 0;short right = 0;if (_frame._the_char._up != 0){up = 1;}if (_frame._the_char._left != 0){left = sizeof(CHAR);}if (_frame._the_char._down != 0){down = 1;}if (_frame._the_char._right != 0){right = 1;}_menu.setPos(_frame._the_char._x + left + _compare_x, _frame._the_char._y + up + _compare_y);}protected:FRAME _frame;MENU _menu;short _compare_x = 0;short _compare_y = 0;bool _staticInit = false;};typedef console_screen_menu<int(*)(), console_screen_menu_operate<int(*)()>, frame, signed char, const char*> menu;typedef console_screen_menu<int(*)(), console_screen_menu_operate<int(*)()>, wframe, wchar_t, const wchar_t*> wmenu;
}
text
console_screen_text_base.h
#pragma once#include <vector>
#include <utility>
#include <cassert>
#include <iostream>namespace my
{template<class STRING, class CH>class console_screen_text_base{template<class TEXTCHAR, class FRAME, class STRING, class CHAR>friend class console_screen_text;public:console_screen_text_base(short x, short y, short high = 10, short wide = 10, int textNum = 1):_text_num(textNum, std::pair<STRING, short>(nullptr, 0)),_x(x),_y(y),_high(high),_wide(wide){assert(textNum > 0);assert(high > 0 && wide > 0);assert(x >= 0 && y >= 0);}void setText(int theTextRank, STRING theText, short frontDistance){assert(theTextRank > 0);assert(theText != nullptr && frontDistance >= 0);_text_num[theTextRank - 1] = { theText, frontDistance };}void setRowSpace(int row){assert(row >= 0);_row_space = row;}void setHideAndWide(int high, int wide){assert(high > 0 && wide > 0);_high = high;_wide = wide;}void showNoCheck(){if (sizeof(CH) == sizeof(signed char)){textShowClean((void(*)(STRING))&getCout, true);}else{textShowClean((void(*)(STRING)) & getWcout, true);}}void cleanNoCheck(){if (sizeof(CH) == sizeof(signed char)){textShowClean((void(*)(STRING)) & getCout, false);}else{textShowClean((void(*)(STRING)) & getWcout, false);}}void cleanAndCheck(){if (sizeof(CH) == sizeof(signed char)){textShowCleanAndCheck((void(*)(CH)) & getCoutC, false);}else{textShowCleanAndCheck((void(*)(CH)) & getWcoutC, false);}}void showAndCheck(){if (sizeof(CH) == sizeof(signed char)){textShowCleanAndCheck((void(*)(CH)) & getCoutC, true);}else{textShowCleanAndCheck((void(*)(CH)) & getWcoutC, true);}}void setPos(short x, short y){assert(x >= 0 && y >= 0);_x = x;_y = y;}protected://文本长度受宽度限制,过长会换行void textShowCleanAndCheck(void(*outfuncString)(CH), bool isShow){int countPosY = 0;int wideLine = _wide;if (sizeof(CH) == 2){wideLine /= 2;}for (int i = 0; i < _text_num.size(); ++i){if (i != 0){countPosY += _row_space;}if (_text_num[i].first == nullptr){return;}int len = theStrlen(_text_num[i].first);int j = 0;int printIndex = 0;if (sizeof(CH) == 1){printIndex = _text_num[i].second;}else{printIndex = _text_num[i].second % 2;printIndex = _text_num[i].second / 2;}SetPos(_x + _text_num[i].second, _y + i + countPosY);while (j < wideLine - printIndex){if (isShow == true){outfuncString(_text_num[i].first[j]);}else{CH blank = 0;if (sizeof(CH) == 2){blank = L' ';outfuncString(blank);outfuncString(blank);}else{blank = ' ';outfuncString(blank);}}++j;}++countPosY;while (printIndex < len){SetPos(_x, _y + i + countPosY);printIndex = j;int maxSize = wideLine + printIndex;if (maxSize > len){maxSize = len;}while (j < maxSize){if (isShow == true){outfuncString(_text_num[i].first[j]);}else{CH blank = 0;if (sizeof(CH) == 2){blank = L' ';outfuncString(blank);outfuncString(blank);}else{blank = ' ';outfuncString(blank);}}++j;}if (j < len){++countPosY;}}}}void textShowClean(void(*outfuncString)(STRING), bool isShow){int countPosY = 0;for (int i = 0; i < _text_num.size(); ++i){if (i != 0){countPosY += _row_space;}SetPos(_x + _text_num[i].second, _y + i + countPosY);if (_text_num[i].first == nullptr){return;}if (isShow == true){outfuncString(_text_num[i].first);}else{int len = theStrlen(_text_num[i].first);if (sizeof(CH) == 1){std::cout << std::string(len, ' ');}else{std::wcout << std::wstring(len * 2, L' ');}}}}static void getWcout(STRING str1){std::wcout << str1;}static void getCout(STRING str1){std::cout << str1;}static void getWcoutC(CH ch){std::wcout << ch;}static void getCoutC(CH ch){std::cout << ch;}protected:std::vector<std::pair<STRING, short>> _text_num; // 文本存储short _row_space = 0; // 行距short _x;short _y;short _high;short _wide; typedef size_t(*p_T_char)(STRING);p_T_char theStrlen = sizeof(CH) == sizeof(signed char) ? (p_T_char)&strlen : (p_T_char)&wcslen;};typedef console_screen_text_base<const char*, signed char> text_base;typedef console_screen_text_base<const wchar_t*, wchar_t> wtext_base;}
console_screen_text.h
#pragma once#include "console_screen_frame.h"
#include "console_screen_text_base.h"namespace my
{template<class TEXTCHAR, class FRAME, class STRING, class CHAR>class console_screen_text{public:console_screen_text(short x, short y, short high = 10, short wide = 20, int textNum = 1):_text(x, y, high, wide, textNum), _frame(x, y, high, wide){;}public: // 静态准备void staticInit(bool yes = true){_staticInit = yes;}bool alreadyStaticInit(){return _staticInit;}public: // 有关文本与框架void setPosCompare(short x, short y){assert(x >= 0);assert(y >= 0);_compare_x = x;_compare_y = y;setTextPos(_text._x + x, _text._y + y);}void checkPosFrameWithText(){if (_frame._the_char._x != _text._x && _frame._the_char._y != _text._y){return;}short up = 0;short down = 0;short left = 0;short right = 0;if (_frame._the_char._up != 0){up = 1;}if (_frame._the_char._left != 0){left = sizeof(CHAR);}if (_frame._the_char._down != 0){down = 1;}if (_frame._the_char._right != 0){right = 1;}setTextPos(_frame._the_char._x + left + _compare_x, _frame._the_char._y + up + _compare_y);_text._high = _frame._the_char._high - up * 2;_text._wide = _frame._the_char._wide - left * 2;}void setAndCheckPos(int x, int y){_frame.setPos(x, y);_text.setPos(x, y);checkPosFrameWithText();}void show(){_frame.frameShow();_text.showNoCheck();}void showAndCheck(){_frame.frameShow();_text.showAndCheck();}void clean(){_frame.frameClean();_text.cleanNoCheck();}void cleanAndCheck(){_frame.frameClean();_text.cleanAndCheck();}public: // 只关于文本的void setTextPos(short x, short y){_text.setPos(x, y);}//void showAndCheck()//{// _text.showAndCheck();//}//void showButNoCheck()//{// _text.showButNoCheck();//}void setHideAndWide(int high, int wide){_text.setRowSpace(high, wide);}void setRowSpace(int row){_text.setRowSpace(row);}void setText(int theTextRank, STRING text, short frontDistance){_text.setText(theTextRank, text, frontDistance);}public: // 只关于框架的void setFrameSide(CHAR up, CHAR down, CHAR left, CHAR right){_frame.setSide(up, down, left, right);checkPosFrameWithText();}void setFrameCorner(CHAR top_left, CHAR bottom_left, CHAR top_right, CHAR bottom_right){_frame.setCorner(top_left, bottom_left, top_right, bottom_right);checkPosFrameWithText();}void setFrameNumWord(int number){_frame.numWord(number);}void setFrameWord(int pos, STRING str1, signed char direction, short distance){_frame.setWord(pos, str1, direction, distance);}void setFrameRecallWord(int pos){_frame.recallWord(pos);}protected:TEXTCHAR _text;FRAME _frame;short _compare_x = 0;short _compare_y = 0;bool _staticInit = false;};typedef console_screen_text<text_base, frame, const char*, signed char> text;typedef console_screen_text<wtext_base, wframe, const wchar_t*, wchar_t> wtext;}
四、代码参考
后续可能会出一份使用菜单库的博客,这里只给一个菜单供大家参考。
#include "console_screen_menu.h"
#include <iostream>int isQuit()
{return 1;
}int main()
{std::wcout.imbue(std::locale("zh_CN"));my::HideCursor();static my::wmenu isATest(2, 1, 5, 10, 2, 1, true);if (isATest.alreadyStaticInit() == false){isATest.setMenuOption(1, 1, "开始", 0, 0);isATest.setMenuOption(2, 1, "结束", 0, 0);isATest.setFrameSide(L'□', L'■', L'○', L'●');isATest.setFrameCorner(L'△', L'▲', L'▽', L'▼');isATest.setMenuBackgroundSpace(1, 1, 0, 2);isATest.setMenuBackgroundSpace(2, 1, 0, 2);isATest.setOperateSpace(1, 1, 2, 0);isATest.setOperateSpace(2, 1, 2, 0);isATest.setMenuButton(2, 1, isQuit);isATest.staticInit(true);}int operWay = 1;isATest.show();if (operWay == 1){isATest.operateWay(my::keyboard);}else{isATest.operateWay(my::mouse);}return 0;
}