软件工程专业在读,,收到了老师的作业 qwq

第一次碰算法题以外的东西,,有点有趣诶 (๑Ő௰Ő๑)

就是让做一个这种菜单:

<img src="https://s1.ax1x.com/2020/10/15/0TO3kT.png" width="500px">

敲一下回车是这样子:

<img src = "https://s1.ax1x.com/2020/10/15/0TXTVx.png" width = "500px" >

看上去不是很难的亚子,,get 到键盘输入的时候,直接清屏再输出新的菜单样子即可,,

getch() 会获取键盘事件并返回按键的 ASCII 码值,,按下方向键需要读两次,第一次是 - 32 (224)(八位存储,正负区别在有无符号 qwq) 第二次对应向上 80, 向下 72 。

随手写了一下伪代码:

	i = 1 //行数 
	print //输出菜单1 
	while (1)
        char op = getch();
        if (op == -32) //方向键 
        	char op1 = getch(); //获取方向
        	if (op1 == 80)
        		i++;
        		//记得控制 i 范围 
			else if (op1 == 72)
				同上
			system("cls");
			switch (i)
				输出对应菜单 
		if (op == 13) //回车 
			system("cls");
			if (i == 4) //选择了退出 
				break;
			else
				输出“选择了i”,按回车返回 
				while (getch() == 13)
					switch (i)
						输出对应菜单 
					break;

好像这样就完事了的说 (๑°3°๑)

不过 "输出对应菜单" 那个地方好像要把那个长长的菜单复 制 四 次 _(:з」∠)_

这样写起来根本不优雅啊喂 (ノ =Д=) ノ

破案:被同学用辣 —— 么长的宏 搞掉了需要复制四次的问题 %%%

咱就稍微找了找,好像有个控制光标位置的东西,,

那岂不是就可以拆成两块了欸嘿嘿,,

  • 输出菜单(不含 '>'‘)
  • 在指定位置输出 '>' 符号

有个 Windows API 中定义的结构体类型 COORD 表示字符在控制台屏幕上的坐标

typedef struct_COORD
{
    SHORT X; // 水平坐标(第几列)
    SHORT Y; // 垂直坐标(第几行)
} COORD;

再加上一堆 Windows API 函数,就能搞这个了:

void Cur_Print(int p) // 改变光标位置,输出 '>',p 表示在 '>' 在菜单的第行
{
    int x = 13, y = 3;
    y += p;
    COORD pos = {x, y};
    HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE); // 获取标识设备的句柄(看不懂呜呜呜..
    SetConsoleCursorPosition(hOutput, pos); // 定位光标位置
    printf("\b>");
}

光标一直在闪,好难受,隐藏掉:

void Hide_Cursor() // 隐藏光标闪烁
{
    HANDLE Handle = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO CursorInfo;
    GetConsoleCursorInfo(Handle, &CursorInfo); // 获取控制台光标信息
    CursorInfo.bVisible = 0; // 不可见
    SetConsoleCursorInfo(Handle, &CursorInfo); // 设置控制台光标状态
}

加上一堆魔改,,就搞出来了。。虽然还是百行。。不过看上去优雅多啦 (´▽`) ノ♪

初次体验使用系统 API 诶,,

code: (血的教训以后一定要加注释 orz)

#include <stdio.h>
#include <stdlib.h>
#include <windows.h>
#include <conio.h>
#include <time.h>
void Menu_Print() // 打印没 '>' 的菜单框框
{
    puts("*********************************************\n*                                           *\n*          游标式屏幕菜单示例               *\n*                                           *\n*             菜单项一                      *\n*             菜单项二                      *\n*             菜单项三                      *\n*             退出                          *\n*                                           *\n*********************************************\n按上下方向键改变选择的菜单项,按回车键执行选择的功能...:\n");
}
void Cur_Print(int p) // 改变光标位置,输出 '>'
{
    int x = 13, y = 3;
    y += p;
    COORD pos = {x, y};
    HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hOutput, pos);
    printf("\b>");
}
void Hide_Cursor() // 隐藏光标闪烁
{
    HANDLE Handle = GetStdHandle(STD_OUTPUT_HANDLE);
    CONSOLE_CURSOR_INFO CursorInfo;
    GetConsoleCursorInfo(Handle, &CursorInfo);
    CursorInfo.bVisible = 0;
    SetConsoleCursorInfo(Handle, &CursorInfo);
}
void Result_Print(int x)
{
    system("cls");
    if (x == 1)
        printf("选择了第1项菜单,按回车键返回...\n");
    else if (x == 2)
        printf("选择了第2项菜单,按回车键返回...\n");
    else if (x == 3)
        printf("选择了第3项菜单,按回车键返回...\n");
    else
        exit(0);
}
void Enter_()
{
    while (1)
    {
        if (kbhit())
        {
            char op1 = getch();
            if (op1 == 13)
                return;
        }
        Sleep(200);
    }
}
void Cur_Process(int move) // 处理光标移动
{
    static int Pos = 1;
    if (move == 233)
    {
        Result_Print(Pos);
        Enter_();
        return;
    }
    Pos += move;
    if (Pos <= 0) // 保证范围在 1 至 4
        Pos = 4;
    if (Pos >= 5)
        Pos = 1;
    Cur_Print(Pos);
}
void Update() // 持续获取键盘信息,更新地图
{
    while (1)
    {
        if (kbhit())
        {
            char op1 = getch();
            if (op1 == 13)
            {
                Cur_Process(233);
                system("cls");
                Menu_Print();
                Cur_Process(0);
                continue;
            }
            char op = getch();
            system("cls");
            Menu_Print();
            if (op == 72)
                Cur_Process(-1);
            else if (op == 80)
                Cur_Process(1);
            else
                Cur_Process(0);
        }
        Sleep(200);
    }
}
int main()
{
    Menu_Print();
    Cur_Print(1); //'>' 位置初始化为 1
    Hide_Cursor();
    Update();
    return 0;
}
更新于