C/C++ 光标:键盘上下键实现菜单移动

思维导图

C/C++ 光标:键盘上下键实现菜单移动_第1张图片
.
不想听过程直接目录移动到代码实现
.

文章目录

    • 思维导图
    • 1.光标移动函数gotoxy()
    • 2.获取键盘键值:_kbhit()函数、_getch()函数
    • 2.1 _kbhit()函数
    • **2.2_getch()函数**
    • 3.菜单内容
    • 3.1通过循环来接收输入
    • 3.2光标移动
    • 3.3 注意事项
    • 代码实现

.

1.光标移动函数gotoxy()

void gotoxy(int xpos, int ypos)
{
	COORD scrn;
	HANDLE hOuput = GetStdHandle(STD_OUTPUT_HANDLE);
	scrn.X = xpos; scrn.Y = ypos;
	SetConsoleCursorPosition(hOuput, scrn);
}

作用就是移动光标到 (xpos,ypos),控制台的输出都是在光标后的

输出案例

cout << "hello " << endl;
	gotoxy(5, 5);
	cout << "world!" << endl;

C/C++ 光标:键盘上下键实现菜单移动_第2张图片

2.获取键盘键值:_kbhit()函数、_getch()函数

2.1 _kbhit()函数

C/C++ 光标:键盘上下键实现菜单移动_第3张图片
执行第17行代码时我并没有在键盘按下任何键
在这里插入图片描述
在这里插入图片描述
通过调试可以知道:_kbhit()函数用于检查键盘是否有输入,如果有则返回非0,否则返回0

.
.

2.2_getch()函数

C/C++ 光标:键盘上下键实现菜单移动_第4张图片

在这里插入图片描述在这里插入图片描述
通过调试发现,通过_getch()函数输入的内容 不会出现在控制台上

当键盘输入 ’ ↑ ’ 时,ch赋值为-32,
第二轮循环:缓冲区又为ch赋值72
这个-32应该是键盘有输入的一个标志,
而72是’ ↑’ 对应的ASCII码

这里不在一 一举例,’ ↓ '的ASCII码为80

3.菜单内容

这里用string数组来存菜单内容,用index来表示菜单的下标

string select[] = { "选项1","选项2","退出3" };
int index = 0;

输出菜单的内容

int main() 
{
	int index = 0;
	char ch;
	string select[] = { "选项1","选项2","退出3" };
	string str = "-> ";
	gotoxy(5, 1);
	cout << "enter ↑ ↓ to control system" << endl;
	for (int i = 0; i < 3; i++) {
		gotoxy(9, 3 + i);
		cout << select[i];
	}
	gotoxy(5, 3);
	cout << str+"     "+select[0];
}

C/C++ 光标:键盘上下键实现菜单移动_第5张图片

3.1通过循环来接收输入

.

 while (true) {
		if (_kbhit()) {
			ch = _getch();//not print at screen
			if (ch == 72 || ch == 80 || ch == '\r') 
			{
				if (ch == 27) {//esc
					//...
					return -1;
				}
				else if (ch == 72) {//up
					//...执行的语句
					index--;
				}
				else if (ch == 80) {//down
                    //...执行的语句
					index++;
				}
				if (index < 0) {
					index = 2;
				}
				else if (index > 2) {
					index = 0;
				}
			}
			
		}
	}

3.2光标移动

要实现上下移动最重要的是:新内容的显示与旧内容的擦除


擦除旧内容:
.
这里就能体现用index来选择菜单的内容的原因:
.
以按下键盘的 ’ ↓ ’ 键 来举例,用’ -> ‘来表示当前选择
.
我们希望’->'移到下一行,则这里的index是要自增的
.
同时清楚我们的当前行
.
所以这里我们需要的操作就是
.

	// 这里的 %*c 表示79个' ',可以起到清除当前行的效果,79是随便设置的
	printf("\r%*c\r", 79, ' ');
	
	gotoxy(9, 3 + index);
	cout << select[index];
	index--;

上移也是同理。


显示新内容
.
我这里为了与没有被选中的内容作区分,将被选中的内容的输出右移了一部分
.
被选中的就是这个效果:
.
C/C++ 光标:键盘上下键实现菜单移动_第6张图片
因为无论是上移还是下移,index都已经自 增/减 过了
.
所以我们只需要将光标移动到当前行(其实是按下按键时的 上/下 一行)
.
输出我们选中的标志 ’ -> ’ 以及菜单内容
.
可以设置一个延时,过渡自然一点,但有没有全凭你自己选择,没有也无影响
.

	gotoxy(5, 3 + index);
	cout << "             ";
	Sleep(100);
	cout << str + select[index];

3.3 注意事项

.
我们的index并不能无限的自增和自减
.
不仅仅是菜单内容有限,如果不加限制的自增和自减会导致数组越界
.
这里添加符合直觉的限制
.
如果是第一个菜单,上移则选中最后一个菜单项,最后一个菜单项下移则选中第一个菜单项
.
我这里的菜单项只有3个,所以数组的最大下标就是:2

		if (index < 0) {
			index = 2;
		}
		else if (index > 2) {
			index = 0;
		}

代码实现

#include 
#include 
#include 
#include 
using namespace std;
void gotoxy(int xpos, int ypos)
{
	COORD scrn;
	HANDLE hOuput = GetStdHandle(STD_OUTPUT_HANDLE);
	scrn.X = xpos; scrn.Y = ypos;
	SetConsoleCursorPosition(hOuput, scrn);
}
int main() 
{
	int index = 0;
	char ch;
	string select[] = { "选项1","选项2","退出3" };
	string str = "-> ";
	gotoxy(5, 1);
	cout << "enter ↑ ↓ to control system" << endl;
	for (int i = 0; i < 3; i++) {
		gotoxy(9, 3 + i);
		cout << select[i];
	}
	gotoxy(5, 3);
	cout << str+"     "+select[0];



	while (true) {
		if (_kbhit()) {
			ch = _getch();//not print at screen
			if (ch == 72 || ch == 80 || ch == '\r') 
			{
				if (ch == 27) {//esc
					cout << "exit system" << endl;
					Sleep(2000);
					return -1;
				}
				else if (ch == 72) {//up
					printf("\r%*c\r", 79, ' ');
					gotoxy(9, 3 + index);
					cout << select[index];
					index--;
				}
				else if (ch == 80) {//down
					printf("\r%*c\r", 79, ' ');
					gotoxy(9, 3 + index);
					cout << select[index];
					index++;
				}
				if (index < 0) {
					index = 2;
				}
				else if (index > 2) {
					index = 0;
				}
			}
			gotoxy(5, 3 + index);
			cout << "             ";
			Sleep(100);
			cout << str + select[index];
			if (ch == '\r') {
				return index;
			}
		}
	}
}

你可能感兴趣的:(数据结构与算法,C/C++,c语言,c++)