You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

C++控制台菜单优化:实现箭头键选择与选中项文字变色

实现上下箭头切换的高亮选中主菜单(C++ Windows)

要实现上下箭头切换菜单并高亮选中项,我们需要利用Windows控制台API控制文本颜色,同时重构菜单交互逻辑,具体实现如下:

核心修改点

  • 使用SetConsoleTextAttribute设置文本颜色,通过GetStdHandle获取控制台句柄
  • 将菜单选项封装为数组,便于管理选中状态
  • 监听上下箭头按键(VK_UP/VK_DOWN)循环切换选中索引
  • 回车确认选中项,执行对应功能

完整修改后的代码

#include <iomanip>
#include <iostream>
#include <string.h>
#include <Windows.h>
#include <conio.h>
#include <bits/stdc++.h>
#include <vector>
#include <fstream>

using namespace std;

vector<pair<int, string>> days{{0,"SATURDAY"}, {1, "SUNDAY"}, {2,"MONDAY"}, {3,"TUESDAY"},
                            {4,"WEDNESDAY"}, {5,"THURSDAY"}, {6,"FRIDAY"}};

// 定义菜单选项结构体
struct MenuItem {
    int id;
    string text;
};

// 获取控制台句柄,用于设置文本颜色
HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);

bool validDate(int d, int m, int y, char c)
{
    if(c == '/')
    {
        if(y >= 1 && y <= 2999)
        {
            if(m >= 1 && m <= 12)
            {
                if(d >= 1 && d <= 31)
                {
                    if( (d >= 1 && d <= 30) && (m == 4|| m == 6|| m == 9|| m == 11))
                        return true;
                    else if((d >= 1 && d <= 31) && (m == 1 || m == 3 || m == 5 || m == 7 || m == 8|| m == 10 ||m == 12))
                        return true;
                    else if((d >= 1 && d <= 28) && (m == 2))
                        return true;
                    else if(d == 29 && m == 2 && ((y % 400 == 0)||(y % 4 == 0 && y % 100 != 0)))
                        return true;
                    else
                        return false;
                }
                else return false;
            }
            else return false;
        }
        else return false;
    }
    else return false;
}

int ZellerCongruence(int givenday, int givenmonth, int givenyear)
{
    if(givenmonth == 1)
    {
        givenmonth = 13;
        givenyear--;
    }
    if(givenmonth == 2)
    {
        givenmonth = 14;
        givenyear--;
    }
    int q = givenday;
    int m = givenmonth;
    int k = givenyear % 100;
    int j = givenyear / 100;
    int h = q + (13 * (m + 1) / 5) + k + (k / 4) + (j / 4) + (5 * j);
    h = h % 7;
    return h;
}

void SubMenu1()
{
    cout << endl << "FIND THE DAY OF THE WEEK FROM THE GIVEN DATE" << endl;
    cout << endl <<  "Notice: Program can only calculate the year from 1 to 2999" << endl;
    cout << endl << "Enter date in dd/mm/yyyy format and press enter: ";
    int givenday, givenmonth, givenyear;
    char c;
    cin >> givenday;
    cin >> c;
    cin >> givenmonth;
    cin >> c;
    cin >> givenyear;
    if(validDate(givenday, givenmonth, givenyear, c) == false)
    {
        cout << "Invalid Date" << endl;
        Sleep(2000);
        return;
    }
    int h = ZellerCongruence(givenday, givenmonth, givenyear);
    cout << endl << "The given day of date is: " << days[h].second << endl;
}

void SubMenu2()
{
    cout << "FIND THE DAY OF THE WEEK AFTER N DAYS FROM THE GIVEN DATE" << endl;
    cout << endl <<  "Notice: Program can only calculate the year from 1 to 2999" << endl;
    cout << endl << "Enter date in dd/mm/yyyy format and press enter: ";
    int givenday, givenmonth, givenyear;
    char c;
    cin >> givenday;
    cin >> c;
    cin >> givenmonth;
    cin >> c;
    cin >> givenyear;
    if(validDate(givenday, givenmonth, givenyear, c) == false)
    {
        cout << "Invalid Date" << endl;
        Sleep(2000);
        return;
    }
    int h = ZellerCongruence(givenday, givenmonth, givenyear);
    int n;
    cout << "Enter the value of n: ";
    cin >> n;
    if(n <= 0)
    {
        cout << "Invalid value, n must be a positive integer." << endl;
        Sleep(2000);
        return;
    }
    h = (h + n) % 7;
    cout << "The day of the week after " << n << " days from the given date is: " << days[h].second << endl;
}

// 绘制菜单,高亮选中项
void DrawMenu(const vector<MenuItem>& menuItems, int selectedIndex)
{
    system("CLS");
    cout << endl << "MAIN MENU" << endl << endl;
    for(int i = 0; i < menuItems.size(); i++)
    {
        if(i == selectedIndex)
        {
            // 设置高亮颜色(白底黑字)
            SetConsoleTextAttribute(hConsole, BACKGROUND_WHITE | FOREGROUND_BLACK);
            cout << menuItems[i].text << endl;
            // 恢复默认颜色(黑底白字)
            SetConsoleTextAttribute(hConsole, FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE);
        }
        else
        {
            cout << menuItems[i].text << endl;
        }
    }
    cout << endl << "Use ↑↓ arrows to navigate, Enter to select" << endl;
}

int main()
{
    // 定义菜单选项列表
    vector<MenuItem> menuItems = {
        {1, "1. Find the day of the week from the given date"},
        {2, "2. Find the day of the week after n days from the given date"},
        {0, "0. Quit the program"}
    };
    int selectedIndex = 0;
    int choice;

    while(true)
    {
        DrawMenu(menuItems, selectedIndex);
        char key = getch();
        
        // 处理箭头键,getch()会先返回0或224,再返回实际键值
        if(key == 0 || key == 224)
        {
            key = getch();
            if(key == VK_UP)
            {
                selectedIndex = (selectedIndex - 1 + menuItems.size()) % menuItems.size();
            }
            else if(key == VK_DOWN)
            {
                selectedIndex = (selectedIndex + 1) % menuItems.size();
            }
        }
        else if(key == 13) // 回车键确认选择
        {
            choice = menuItems[selectedIndex].id;
            system("CLS");
            switch(choice)
            {
                case 0:
                    cout << "See you again !" << endl;
                    return 0;
                case 1:
                    SubMenu1();
                    system("pause");
                    break;
                case 2:
                    SubMenu2();
                    system("pause");
                    break;
                default:
                    cout << "Invalid Number..." << endl;
                    system("pause");
                    break;
            }
        }
    }
    return 0;
}

关键说明

  1. 颜色控制:通过SetConsoleTextAttribute设置控制台文本属性,选中项使用白底黑字突出显示,其他项保持默认黑底白字。
  2. 菜单绘制:每次按键后重新绘制菜单,确保选中项的高亮状态正确更新。
  3. 按键处理:箭头键会触发两次getch()调用(先返回前缀码,再返回实际键值),需要捕获VK_UP和VK_DOWN来切换选中索引,回车确认选择。
  4. 循环切换:使用取模运算实现菜单选项的循环切换,避免索引越界。

内容的提问来源于stack exchange,提问作者Hoang Tu Bong Dem

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.11 06:45:54