使用curses为终端文本局部着色,是否有更简便的实现方式?
问题描述
在使用curses库制作终端下拉菜单时,发现ANSI转义码无法生效,必须通过init_pair、attron()和attroff()实现文本着色。但这种方式默认会给整段字符串着色,而我仅需要为文本的局部区域着色。目前只能通过分段打印实现,但代码过于冗长,后期维护会很混乱,有没有更优的解决方法?
现有无效代码:
// ANSI代码在curses中无效,会被当作普通文本显示 printw("%s (\033[1;37m%d\033[0m): \n", message.c_str(), defaultValue.c_str());
现有分段实现方式(代码冗长):
init_pair(1, COLOR_WHITE, COLOR_BLACK); init_pair(2, COLOR_GREEN, COLOR_BLACK); // 分段打印实现局部着色 attron(COLOR_PAIR(2)); printw("%s (", message.c_str()); attroff(COLOR_PAIR(2)); attron(COLOR_PAIR(1)); printw("%d", defaultValue); attroff(COLOR_PAIR(1)); attron(COLOR_PAIR(2)); printw("): \n"); attroff(COLOR_PAIR(2));
解决方案
1. 封装自定义格式化打印函数
编写一个封装函数,解析带有自定义标记的字符串,自动切换对应颜色属性,避免重复编写attron/attroff代码:
#include <curses.h> #include <string> #include <cstdarg> // 自定义标记规则:{数字}对应颜色对编号,{0}恢复默认颜色 void formatted_print(const std::string& format, ...) { va_list args; va_start(args, format); char buffer[1024]; vsnprintf(buffer, sizeof(buffer), format.c_str(), args); va_end(args); std::string str(buffer); size_t pos = 0; while (pos < str.size()) { if (str[pos] == '{' && pos + 2 < str.size() && str[pos+2] == '}') { int pair_num = str[pos+1] - '0'; if (pair_num == 0) { attroff(A_COLOR); } else { attron(COLOR_PAIR(pair_num)); } pos += 3; } else { addch(str[pos]); pos++; } } } // 使用示例 int main() { initscr(); start_color(); init_pair(1, COLOR_WHITE, COLOR_BLACK); init_pair(2, COLOR_GREEN, COLOR_BLACK); std::string message = "选项"; int defaultValue = 5; formatted_print("{2}%s ({1}%d{2}): \n", message.c_str(), defaultValue); refresh(); getch(); endwin(); return 0; }
2. 用宏封装属性切换逻辑
如果不想写复杂的解析函数,可以用宏简化重复的attron/attroff操作:
#define COLOR_PRINT(pair_num, fmt, ...) do { \ attron(COLOR_PAIR(pair_num)); \ printw(fmt, ##__VA_ARGS__); \ attroff(COLOR_PAIR(pair_num)); \ } while(0) // 使用示例 COLOR_PRINT(2, "%s (", message.c_str()); COLOR_PRINT(1, "%d", defaultValue); COLOR_PRINT(2, "): \n");
3. 按区域封装打印逻辑
针对固定结构的文本,直接封装成按区域着色的函数:
void print_label_with_value(const std::string& label, int label_pair, int value, int value_pair) { attron(COLOR_PAIR(label_pair)); printw("%s (", label.c_str()); attroff(COLOR_PAIR(label_pair)); attron(COLOR_PAIR(value_pair)); printw("%d", value); attroff(COLOR_PAIR(value_pair)); attron(COLOR_PAIR(label_pair)); printw("): \n"); attroff(COLOR_PAIR(label_pair)); } // 使用示例 print_label_with_value(message, 2, defaultValue, 1);
内容的提问来源于stack exchange,提问作者Tetie
相关产品推荐
相关产品推荐

