【课程设计】Windows控制台上的交互界面(通过c/c++,在windows控制台实现选择菜单(可通过方向键选择))

【课程设计】通过c/c++,在控制台实现选择菜单(可通过方向键选择)

前言

以前做课设的时候,费了很大功夫,在windows控制台实现方向键选择菜单。希望可以在这里总结一下,也欢迎大家一起交流学习。

正文

SetConsoleTextAttribute函数

  • 以下摘自百度百科 传送门
    • SetConsoleTextAttribute是Windows系统中一个可以设置控制台窗口字体颜色和背景色的计算机函数,该函数被广泛应用于软件开发中。
      使用此函数前,必须包含Windows.h头文件,即#include <Windows.h>。
    • 原型
      • BOOL SetConsoleTextAttribute(HANDLE hConsoleOutput, WORD wAttributes);
  • 宏定义以下代码:
#define IN_RED SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), \
                                       BACKGROUND_RED |                 \
                                           BACKGROUND_INTENSITY)
#define IN_DEFAULT SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), \
                                           FOREGROUND_RED |                 \
                                               FOREGROUND_GREEN |           \
                                               FOREGROUND_BLUE)
  • In_Red,意味着将字体的背景变为红色;而In_DEFAULT,意味着将字体的背景变为默认状态(混合红、绿、蓝)
  • 定义函数:
void ShowInRed()
{
    IN_RED;
    printf("Red\n");
    return;
}
  • 效果展示:
    in_red
  • 我们注意到后面的语句的背景也变红了。怎么解决这个问题呢?我们只需要在printf执行完之后,调用IN_DEFAULT,将字体背景重置为默认色即可。
  • 代码:
void ShowInRed()
{
    IN_RED;
    printf("Red\n");
    IN_DEFAULT;
    return;
}
  • 结果:
    in_red_default

Gotoxy

void Gotoxy(int x, int y)
{
    COORD pos = {x, y};
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hOut, pos);
    return;
}
  • 该函数的用处为将光标移动到(x, y)处

CursorOpr ⋆ ⋆ ⋆ \star\star\star

下面我们重点来讲以下实现原理

  • 原理:通过读取方向键来移动光标,然后用带背景色的字体重新覆盖原本的字体,这样就像是高亮选中了;当离开当前行,选择别的行的时候,就先用默认色覆盖当前行,然后移动光标,高亮覆盖光标后的行,实现退选和再选(如何实现可以看代码注释)
  • 代码:
#define UPKEY 72
#define DOWNKY 80 //宏定义上下方向键的ascii值
void Menu() //主菜单
{
    printf("欢迎来到学生奖学金管理系统\n");
    printf("**************************************************\n");
    printf("0) 退出程序\n");
    printf("1) 录入学生信息\n");
    printf("2) 显示全部学生信息\n");
    printf("3) 查找学生信息\n");
    printf("4) 删除学生信息\n");
    printf("5) 追加学生信息\n");
    printf("6) 修改学生信息\n");
    printf("7) 统计学生信息\n");
    printf("8) 奖学金名单\n");
    printf("9) 保存文件\n");
    printf("10)备份文件\n");
    printf("**************************************************\n");
    printf("请使用↑、↓和enter来实现选择和执行命令\n");
    printf("或者输入每个命令前面的数字来执行命令<0 - 9>\n");
    return;
}

void CursorPos1(int x) //光标覆盖菜单
{
    switch (x)
    {
    case 0:
        printf("0) 退出程序                                       ");
        break;
    case 1:
        printf("1) 录入学生信息                                   ");
        break;
    case 2:
        printf("2) 显示全部学生信息                               ");
        break;
    case 3:
        printf("3) 查找学生信息                                   ");
        break;
    case 4:
        printf("4) 删除学生信息                                   ");
        break;
    case 5:
        printf("5) 追加学生信息                                   ");
        break;
    case 6:
        printf("6) 修改学生信息                                   ");
        break;
    case 7:
        printf("7) 统计学生信息                                   ");
        break;
    case 8:
        printf("8) 奖学金名单                                     ");
        break;
    case 9:
        printf("9) 保存文件                                       ");
        break;
    case 10:
        printf("10)备份文件                                       ");
    }
    return;
}

int CursorOpr(int line, int deta, int lower, int upper, void (*p)(int))
{
/*
line:当前光标所在行数
deta:行数与菜单选项的差值。比如在main菜单中选项(0)在第2行(行数从0开始计算),所以deta等于2,即2 - 0
upper, lower:选项的上下界
(*P)(int):函数指针,选择哪个覆盖菜单
*/
    char c1, c2;
    Gotoxy(0, line);
    do
    {
        c2 = getch();
        if (c2 == DOWNKEY)
        {
            Gotoxy(0, line);
            IN_DEFAULT; //选择默认色
            (*p)(line - deta); //覆盖,实现退选
            if (line == upper) //如果已经到了上界,则返回下界,实现滚动高亮
                line = lower;
            else
                ++line; //行数+1
            Gotoxy(0, line);
            IN_CYAN;
            (*p)(line - deta);
        }
        if (c2 == UPKEY)
        {
            Gotoxy(0, line);
            IN_DEFAULT;
            (*p)(line - deta);
            if (line == lower)
                line = upper;
            else
                --line;
            Gotoxy(0, line);
            IN_CYAN;
            (*p)(line - deta);
        }
    } while ((c1 = getch()) != '\r');
    IN_RED;
    Gotoxy(0, line);
    (*p)(line - deta);
    IN_DEFAULT;
    return line - deta;
}

menu

TheConsoleSize

void TheConsoleSize(int width, int height)
{
    char chCmd[32];
    sprintf(chCmd, "mode con cols=%d lines=%d", width, height);
    system(chCmd);
    return;
}
  • 该函数的用处为调整控制台的大小

The Whole Code

#include <bits/stdc++.h>
#include <conio.h>
#include <windows.h>
using namespace std;
#define IN_RED SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), \
                                       BACKGROUND_RED |                 \
                                           BACKGROUND_INTENSITY)
#define IN_GREEN SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), \
                                         BACKGROUND_GREEN |               \
                                             BACKGROUND_INTENSITY)
#define IN_BULE SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), \
                                        BACKGROUND_BLUE |                \
                                            BACKGROUND_INTENSITY)
#define IN_YELLOW SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), \
                                          BACKGROUND_RED |                 \
                                              BACKGROUND_GREEN |           \
                                              BACKGROUND_INTENSITY)
#define IN_CYAN SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), \
                                        BACKGROUND_GREEN |               \
                                            BACKGROUND_BLUE |            \
                                            BACKGROUND_INTENSITY)
#define IN_MAGENTA SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), \
                                           BACKGROUND_BLUE |                \
                                               BACKGROUND_RED |             \
                                               BACKGROUND_INTENSITY)
#define IN_WHITE SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), \
                                         BACKGROUND_RED |                 \
                                             BACKGROUND_GREEN |           \
                                             BACKGROUND_BLUE |            \
                                             BACKGROUND_INTENSITY)
#define IN_DEFAULT SetConsoleTextAttribute(GetStdHandle(STD_OUTPUT_HANDLE), \
                                           FOREGROUND_RED |                 \
                                               FOREGROUND_GREEN |           \
                                               FOREGROUND_BLUE)
#define UPKEY 72
#define DOWNKEY 80

void Menu()
{
    printf("欢迎来到学生奖学金管理系统\n");
    printf("**************************************************\n");
    printf("0) 退出程序\n");
    printf("1) 录入学生信息\n");
    printf("2) 显示全部学生信息\n");
    printf("3) 查找学生信息\n");
    printf("4) 删除学生信息\n");
    printf("5) 追加学生信息\n");
    printf("6) 修改学生信息\n");
    printf("7) 统计学生信息\n");
    printf("8) 奖学金名单\n");
    printf("9) 保存文件\n");
    printf("10)备份文件\n");
    printf("**************************************************\n");
    printf("请使用↑、↓和enter来实现选择和执行命令\n");
    printf("或者输入每个命令前面的数字来执行命令<0 - 9>\n");
    return;
}

void CursorPos1(int x)
{
    switch (x)
    {
    case 0:
        printf("0) 退出程序                                       ");
        break;
    case 1:
        printf("1) 录入学生信息                                   ");
        break;
    case 2:
        printf("2) 显示全部学生信息                               ");
        break;
    case 3:
        printf("3) 查找学生信息                                   ");
        break;
    case 4:
        printf("4) 删除学生信息                                   ");
        break;
    case 5:
        printf("5) 追加学生信息                                   ");
        break;
    case 6:
        printf("6) 修改学生信息                                   ");
        break;
    case 7:
        printf("7) 统计学生信息                                   ");
        break;
    case 8:
        printf("8) 奖学金名单                                     ");
        break;
    case 9:
        printf("9) 保存文件                                       ");
        break;
    case 10:
        printf("10)备份文件                                       ");
    }
    return;
}

void TheConsoleSize(int width, int height)
{
    char chCmd[32];
    sprintf(chCmd, "mode con cols=%d lines=%d", width, height);
    system(chCmd);
    return;
}

void Gotoxy(int x, int y)
{
    COORD pos = {x, y};
    HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE);
    SetConsoleCursorPosition(hOut, pos);
    return;
}

int CursorOpr(int line, int deta, int lower, int upper, void (*p)(int))
{
/*
line:当前光标所在行数
deta:行数与菜单选项的差值。比如在main菜单中选项(0)在第2行(行数从0开始计算),所以deta等于2,即2 - 0
upper, lower:选项的上下界
(*P)(int):函数指针,选择哪个覆盖菜单
*/
    char c1, c2;
    Gotoxy(0, line);
    do
    {
        c2 = getch();
        if (c2 == DOWNKEY)
        {
            Gotoxy(0, line);
            IN_DEFAULT; //选择默认色
            (*p)(line - deta); //覆盖,实现退选
            if (line == upper) //如果已经到了上界,则返回下界,实现滚动高亮
                line = lower;
            else
                ++line; //
            Gotoxy(0, line);
            IN_CYAN;
            (*p)(line - deta);
        }
        if (c2 == UPKEY)
        {
            Gotoxy(0, line);
            IN_DEFAULT;
            (*p)(line - deta);
            if (line == lower)
                line = upper;
            else
                --line;
            Gotoxy(0, line);
            IN_CYAN;
            (*p)(line - deta);
        }
    } while ((c1 = getch()) != '\r');
    IN_RED;
    Gotoxy(0, line);
    (*p)(line - deta);
    IN_DEFAULT;
    return line - deta;
}

int main()
{
    int n, line = 2; // 对应menu()的1)
    char c1, c2;
    bool b;
    while (1)
    {
        system("cls");
        TheConsoleSize(80, 50);
        Menu();
        if ((c1 = getch()) == -32)
        {
            n = CursorOpr(line, 2, 2, 12, CursorPos1);
        }
        else
        {
            char tmp;
            scanf("%c", &tmp);
            if (tmp >= '0' && tmp <= '9')
                n = tmp - '0';
            else
                n = tmp;
        }
    }
    system("pause");
    return 0;
}

结语

参考资料

每日一句

我有迷魂招不得,雄鸡一声天下白。
少年心事当拏云,谁念幽寒坐呜呃。
——李贺《致酒行》

  • 6
    点赞
  • 21
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值