ncurses颜色无法生效求助:attron/wattron等函数均无效
解决NCurses中颜色设置无效的问题
你遇到的核心问题是你在操作自定义窗口win,但却用了针对全局stdscr的attron()/attroff()函数——这些属性设置不会自动应用到你创建的newwin()窗口上,必须使用窗口专属的属性操作函数。
问题根源拆解
attron(COLOR_PAIR(1))只会修改全局窗口stdscr的属性,而你实际在自定义窗口win上调用mvwaddch(),所以颜色根本没生效;- 原代码仅在清除第二个对象时设置了颜色属性,但绘制字符时属性已经被取消,等于白设置;
- 缺少终端颜色支持的前置检查,万一终端不支持颜色,也无法提前知晓问题。
修改后的完整代码
#include "stdio.h" #include "ncurses.h" #include "math.h" #include "unistd.h" #include "stdlib.h" #include <stdbool.h> // 补全bool类型所需头文件 double PI = 3.15927; bool drawObject(WINDOW *win, int **obj, int size, int y, int x); bool clearObject(WINDOW *win, int **obj, int size, int y, int x); bool drawPoint(WINDOW *win, int y, int x, char c); bool drawPoint(WINDOW *win, int y, int x, char c) { bool r = mvwinch(win, y, x) != 0x20; mvwaddch(win, y, x, c); return r; } bool drawObject(WINDOW *win, int **obj, int size, int y, int x) { int k; bool r = false; for (k = 0; k < size; ++k) { r |= drawPoint(win, y + obj[k][0], x + obj[k][1], (char)obj[k][2]); } wrefresh(win); return r; } bool clearObject(WINDOW *win, int **obj, int size, int y, int x) { int k; for (k = 0; k < size; ++k) { mvwaddch(win, y + obj[k][0], x + obj[k][1], ' '); } wrefresh(win); return true; // 补全函数声明要求的返回值 } int main(int argc, char **argv) { int k = 0; WINDOW *win, *status; int ox = 40, oy = 20; bool isCrash = false; int obj1_size = 6; int **obj1_def = (int**)malloc(sizeof(int*) * obj1_size); for (k = 0; k < obj1_size; ++k) { obj1_def[k] = (int*)malloc(sizeof(int) * 3); } obj1_def[0][0] = 0; obj1_def[0][1] = 1; obj1_def[0][2] = (int)'\\'; obj1_def[1][0] = 0; obj1_def[1][1] = -1; obj1_def[1][2] = (int)'/'; obj1_def[2][0] = 1; obj1_def[2][1] = 0; obj1_def[2][2] = (int)'W'; obj1_def[3][0] = 0; obj1_def[3][1] = 0; obj1_def[3][2] = (int)'H'; obj1_def[4][0] = -1; obj1_def[4][1] = 0; obj1_def[4][2] = (int)'H'; obj1_def[5][0] = -2; obj1_def[5][1] = 0; obj1_def[5][2] = (int)'A'; double obj1_step = PI / 50; double obj1_t = 1.5; int obj1_a = 4; int obj1_x = 0, obj1_y = 0; double obj2_step = PI / 20; double obj2_t = 0; int obj2_a = 3; int obj2_b = 10; int obj2_x = 0, obj2_y = 0; initscr(); refresh(); // 新增:检查终端是否支持颜色 if (!has_colors()) { endwin(); fprintf(stderr, "终端不支持颜色!\n"); return 1; } if (!can_change_color()) { fprintf(stderr, "终端不允许修改颜色!\n"); } startcolor(); init_pair(1, COLOR_RED, COLOR_BLACK); // 定义颜色对:前景红,背景黑 win = newwin(40, 80, 0, 0); status = newwin(2, 80, 40, 0); wrefresh(win); wrefresh(status); while (true) { // 第一个对象 clearObject(win, obj1_def, obj1_size, obj1_y, obj1_x); obj1_x =(int)(3 * obj1_t * sin(obj1_t * 0.5) * cos(obj1_t)); obj1_y =(int)(2 * obj1_t * cos(obj1_t * 1.5) * cos(obj1_t)); obj1_x += 50; obj1_y += 20; if (obj1_x < 1) { obj1_x = 1; } if (obj1_x > 78) { obj1_x = 78; } if (obj1_y < 2) { obj1_y = 2; } if (obj1_y > 38) { obj1_y = 38; } isCrash = drawObject(win, obj1_def, obj1_size, obj1_y, obj1_x); if (isCrash == true) { mvwprintw(status, 0, 0, "[%d, %d] [%d, %d]", obj1_x, obj1_y, obj2_x, obj2_y); mvwprintw(status, 1, 0, "Crash !!!"); break; } obj1_t += obj1_step; if (obj1_t > 17.215) { obj1_t = 1.5; } // 第二个对象 // 关键修改:用窗口专属的wattron/wattroff设置颜色属性 wattron(win, COLOR_PAIR(1)); // 清除旧位置 mvwaddch(win, obj2_y, obj2_x, ' '); mvwaddch(win, obj2_y, obj2_x+1, ' '); mvwaddch(win, obj2_y, obj2_x-1, ' '); mvwaddch(win, obj2_y-1, obj2_x, ' '); mvwaddch(win, obj2_y-1, obj2_x-1, ' '); // 绘制新位置(在属性生效范围内) mvwaddch(win, obj2_y, obj2_x+1, '-'); mvwaddch(win, obj2_y, obj2_x-1, '-'); mvwaddch(win, obj2_y, obj2_x, '-'); mvwaddch(win, obj2_y-1, obj2_x, '\\'); mvwaddch(win, obj2_y-1, obj2_x-1, '\\'); wattroff(win, COLOR_PAIR(1)); wrefresh(win); // 修复笔误:原代码误用obj1_t计算第二个对象位置,改为obj2_t obj2_x =(int)(obj2_a * obj2_t - obj2_b * sin(obj2_t)); obj2_y =(int)(obj2_a - obj2_b * cos(obj2_t)); obj2_y += 20; if (obj2_x < 1) { obj2_x = 1; } if (obj2_x > 78) { obj2_x = 78; } if (obj2_y < 2) { obj2_y = 2; } if (obj2_y > 38) { obj2_y = 38; } isCrash = mvwinch(win, obj2_y, obj2_x+1) != 0x20 || mvwinch(win, obj2_y, obj2_x-1) != 0x20 || mvwinch(win, obj2_y, obj2_x) != 0x20 || mvwinch(win, obj2_y-1, obj2_x) != 0x20 || mvwinch(win, obj2_y-1, obj2_x-1) != 0x20; if (isCrash == true) { mvwprintw(status, 0, 0, "[%d, %d] [%d, %d]", obj1_x, obj1_y, obj2_x, obj2_y); mvwprintw(status, 1, 0, "Crash !!!"); break; } obj2_t += obj2_step; if (obj2_t > 30) { obj2_t = 0; } wmove(win,0,0); mvwprintw(status, 0, 0, "[%d, %d] [%d, %d]", obj1_x, obj1_y, obj2_x, obj2_y); wrefresh(win); wrefresh(status); usleep(100000); } wrefresh(status); getch(); delwin(win); delwin(status); endwin(); for (k = 0; k < obj1_size; ++k) { free(obj1_def[k]); } free(obj1_def); return 0; }
核心修改说明
替换全局属性函数为窗口专属函数:
将attron()/attroff()替换为wattron(win, ...)/wattroff(win, ...),确保颜色属性作用到目标窗口win上。把绘制逻辑包裹在属性生效范围内:
原代码仅在清除时设置颜色,绘制时属性已失效,现在将清除和绘制第二个对象的代码都放在wattron和wattroff之间,保证颜色生效。修复逻辑笔误:
原代码计算第二个对象位置时误用了obj1_t,改为obj2_t,让两个对象的运动逻辑独立。新增终端兼容性检查:
加入has_colors()和can_change_color()检查,提前排查终端不支持颜色的情况。
编译时记得链接ncurses库:
gcc your_code.c -o your_program -lncurses -lm
如果你想给第一个对象也设置颜色,只需要在调用drawObject()前添加wattron(win, COLOR_PAIR(你定义的颜色对编号)),调用后用wattroff取消即可。
内容的提问来源于stack exchange,提问作者weneedtogodeeper
相关产品推荐
相关产品推荐

