本篇文章及库只适用于初学者,如果您的水平已经达到一定程度,这对您来说将会是简单的。
本库的开发目的也主要是针对于自己的一段学习总结,其次是给初学者一个方便的库来构建键盘控制的控制台菜单。

你的控制台是不是还在使用像这样的输入控制?

传统控制台程序

那么为什么不能用像真正游戏一样实现键盘控制的菜单呢?虽然控制台难以实现鼠标操作,但是键盘控制也不难的哇!

不过,这里提供一个简单的库给初学者使用,可以更加方便地完成一个优秀的课程设计之类的作品。

一、库的地址

Github仓库地址。

二、简单使用

你可以直接使用下面的标准样例,代码已经给出了详细的介绍,只需按照自己的需求适当修改即可!

标准构建代码(仅供参考)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
#include "ConsoleMenu.h"

// 键盘事件处理函数
// 参数:
// - 键盘事件对象
// - 控制台菜单对象
// 返回值:无
// 注意:
// 键盘事件对象的定义(仅*号表示重要|仅供参考):
// typedef struct _KEY_EVENT_RECORD//键盘事件结构体
// {
// BOOL bKeyDown; //按键状态,true代表键按下,false代表键释放(*)
// WORD wRepeatCount; //按键次数(*)
// WORD wVirtualKeyCode; //虚拟键(*)
// WORD wVirtualScanCode; //虚拟键扫描码
// union
// {
// WCHAR UnicodeChar; //解释成Unicode宽字符
// CHAR AsciiChar; //解释成ASCII码字符
// } uChar;
// DWORD dwControlKeyState; //控制键状态
// } KEY_EVENT_RECORD;
void OnKeyPressed(KEY_EVENT_RECORD KeyEvent, CONSOLEMENU* cmenu) {

// 利用 KeyEvent.wVirtualKeyCode 判断按键值(具体参考常用虚拟键代码表)
if (KeyEvent.wVirtualKeyCode == VK_UP && // 按下↑键
// 注意:一般按下一个按键后会接收到两次该按键的事件,分别为该按键的按下事件和释放事件。
// 下面的判断:
// 为1表示当前为键按下而不是键释放
KeyEvent.bKeyDown == 1) {

// MenuIndex 表示为被选中的菜单项的索引,所以只要索引在总量的模下减1即可表示选中上移
// MenuListNum 表示当前总共拥有的菜单项总数
cmenu->Menu->MenuIndex = (cmenu->Menu->MenuIndex-1)%cmenu->Menu->MenuListNum;

//重新打印菜单
cmenu->PrintMenu(cmenu->Menu);

} else if (KeyEvent.wVirtualKeyCode == VK_DOWN && // 按下↓键
KeyEvent.bKeyDown == 1) {

// 选择菜单项的索引+1表示选中上移
cmenu->Menu->MenuIndex = (cmenu->Menu->MenuIndex+1)%cmenu->Menu->MenuListNum;

// 重新打印菜单
cmenu->PrintMenu(cmenu->Menu);

} else if (KeyEvent.wVirtualKeyCode == VK_ESCAPE && // 按下ESC键
KeyEvent.bKeyDown == 1) {

// 刷新控制台信息
cmenu->Refresh();
// 退出程序,参数为退出码
// 一般 0 表示正常退出
exit(0);

} else if (KeyEvent.wVirtualKeyCode == VK_RETURN && // 按下回车键
KeyEvent.bKeyDown == 1) {

// 刷新控制台信息
cmenu->Refresh();

// 通过 if 判断按下回车键(确定选中)时索引的值,从而实现不同菜单项的功能
if (cmenu->Menu->MenuIndex == 3) { // 当选中第4个菜单项时,执行对应操作!
// 这里对应[退出游戏]
exit(0);
} else { // 不具体一一实现了,可以运行查看这里的功能
printf("进入[%s]\n", cmenu->Menu->MenuContent[cmenu->Menu->MenuIndex]);
}

} else if (KeyEvent.wVirtualKeyCode == VK_BACK &&
KeyEvent.bKeyDown == 1) {

// 程序打印菜单
cmenu->PrintMenu(cmenu->Menu);

}
}

int main() {
int i;
// 开始吧~Hello World!
printf("Hello World!\n");

// 使用方法介绍
// 创建控制台菜单对象
CONSOLEMENU a;

// 初始化对象
// 参数: 控制台菜单对象的指针
// 返回值: 成功初始化返回0,失败则返回非0值
Init(&a);

// 刷新控制台上的所有信息
// 参数:无
// 返回值:无
a.Refresh();

// 设置控制台规格
// 参数:
// - 控制台的宽(以一个英文字符的宽为基本单位)
// - 控制台的高(以一个英文字符的高为基本单位)
// - 控制台标题(最长 128)
// - 控制台文字颜色(具体可以查表)
// - 控制台背景颜色(具体可以查表)
// 返回值:成功返回0,失败则返回非0值
a.SetConsoleMenuWnd(50, 20, "Demo", GREEN, BLACK);

// 添加一个菜单项
// 参数:新添加菜单项的名称
// 返回值:成功返回0,失败则返回非0值
a.Menu->AddMenuList("开始游戏");
a.Menu->AddMenuList("查看排行");
a.Menu->AddMenuList("规则说明");
a.Menu->AddMenuList("退出游戏");
a.Menu->AddMenuList("待测试项[2]");

// 插入一个菜单项
// 参数:
// - 待插入菜单项的名称
// - 待插入位置的索引(从0开始)
// 返回值:成功返回0,失败则返回非0值
// 注意:这里的菜单项的索引是从0开始计算的!第一个菜单项的名称应该是0,第二个是1,后面以此类推!
a.Menu->InsertMenuList("待测试项[1]", 4);

// 交换两个菜单项的位置
// 参数:
// - 待交换菜单项的索引(从0开始)
// - 待交换菜单项的索引(从0开始)
// 返回值:成功返回0,失败则返回非0值
a.Menu->SwapMenuList(4, 5);

// 删除一个菜单项
// 参数:待删除菜单项的索引(从0开始)
// 返回值:成功返回0,失败则返回非0值
a.Menu->DelMenuList(4);
a.Menu->DelMenuList(4);

// // 这是一个例子关于“如何访问菜单项具体的内容?”
// // 很明显,菜单是以数组的方式存储的,但是并不完全是数组
// for (i = 0; i < a.Menu->MenuListNum; i++) {
// // 通过数组索引访问菜单中的菜单项
// printf("a.Menu.MenuContent[%d]=%s\n", i, a.Menu->MenuContent[i]);
// }

// 打印菜单
// 参数:菜单对象
// 返回值:无
a.PrintMenu(a.Menu);

// 运行键盘事件监听,从而实现键盘控制功能
// 参数:控制台菜单对象
// 返回值:无
// 注意:这里需要重新编写 OnKeyPressed 函数,从而实现自己的功能
RunKeyEvent(&a);

return 0;
}

标准构建样例运行效果截图:
图2.1 构建样例

三、如何使用

相信你注意到了标准构建样例代码第一行的头文件了吧?下面给出导入该库的方法!

3.1 下载库文件

图3.1.1 下载步骤 1
图3.1.2 下载步骤 2

3.2 DEV C++

这里以 DEV C++ 为例子演示一下具体使用方法(小白向)。

3.2.1 构建项目

构建你的项目:
图3.2.1 在 DEVCPP 新建项目

3.2.2 导入库文件

也就是将下载好的文件全部解压到你的项目根目录,例如:
我有一个项目,其文件结构包括以下内容:

原始项目结构
1
2
3
4
Test
├── ConsoleMenu.dev
├── ConsoleMenu.layout
└── main.c

那么,我解压后对应的文件结构应该是:

添加库文件后的项目结构
1
2
3
4
5
6
7
Test/
├── lib/
│ └── ConsoleMenu.a
├── ConsoleMenu.dev
├── ConsoleMenu.h
├── ConsoleMenu.layout
└── main.c

3.2.3 配置项目信息

图3.2.2 项目属性

注意!这里是选择 lib 里面的 ConsoleMenu.a 文件!而这个 lib 文件夹及 ConsoleMenu.aConsoleMenu.h文件据来自在 GITHUB 上下载的 ConsoleMenu.rar,应当是解压到项目根目录后自动有的!
图3.2.3 加入库或者对象

3.2.4导入头文件并编程

最后就是导入头文件并编写你的项目了。
建议使用标准构建代码快速编程~