Ubuntu 22.6下ncurses程序鼠标点击触发printw重复打印问题求助
ncurses鼠标左键点击触发重复打印问题求助
我正在学习ncurses库,在Ubuntu 22.04系统的Gnome终端中运行以下C语言代码时遇到问题:点击指定区域的"Exit"按钮时,MouseLeftClicked函数中的mvprintw会被触发两次,而非预期的一次。我已经在网上搜索类似问题但没找到解决方案,推测是遗漏了ncurses的某些基础知识点,恳请各位帮忙解决。
#include <stdbool.h> #include <time.h> #include <ncurses.h> int main(void); void MouseLeftClicked(int x, int y, char *caption); int main(void) { int ch; bool exit = false; MEVENT event; initscr(); noecho(); cbreak(); keypad(stdscr, TRUE); mousemask(ALL_MOUSE_EVENTS, NULL); clear(); curs_set(0); mvprintw(0, 0, "F1 exits"); start_color(); init_pair(1, COLOR_WHITE, COLOR_BLUE); attron(COLOR_PAIR(1)); mvprintw(10, 1, " Exit "); attroff(COLOR_PAIR(1)); refresh(); do { ch = getch(); if(ch == KEY_MOUSE) { mvprintw(2, 0, "Got KEY_MOUSE"); if(getmouse(&event) == OK) { mvprintw(3, 0, "Got mouse event"); if(event.bstate & BUTTON1_CLICKED) { mvprintw(4, 0, "Got click on button #1"); mvprintw(5, 0, "Mouse position: x=%d y=%d ", event.x, event.y); refresh(); if(event.x > 0 && event.x < 7 && event.y == 10) MouseLeftClicked(event.x+1, event.y+1, " Exit "); ch = 0; } } } if(ch == KEY_F(1)) exit = true; } while(! exit); curs_set(1); endwin(); return 0; } void MouseLeftClicked(int x, int y, char *caption) { struct timespec tim, tim2; tim.tv_sec = 0; tim.tv_nsec = 999999998L; init_pair(1, COLOR_WHITE, COLOR_GREEN); attron(COLOR_PAIR(1)); mvprintw(y, x, "%s", caption); //printw("%s", caption); attroff(COLOR_PAIR(1)); refresh(); //nanosleep(&tim, &tim2); //init_pair(1, COLOR_WHITE, COLOR_BLUE); //attron(COLOR_PAIR(1)); //mvprintw(y, x, " Exit "); //attroff(COLOR_PAIR(1)); }
结果截图:
问题原因与解决方案
问题核心在于两点:
- 鼠标掩码捕获了重复事件:使用
ALL_MOUSE_EVENTS会同时捕获鼠标按下、释放等多个事件,而BUTTON1_CLICKED的判断会在这些事件中重复触发,导致函数被调用两次。 - 重复初始化颜色对:在MouseLeftClicked函数中反复调用
init_pair(1)会干扰颜色对的状态,可能引发界面更新异常。
具体修复步骤:
精简鼠标掩码:将
mousemask(ALL_MOUSE_EVENTS, NULL);改为只捕获需要的点击事件,比如:mousemask(BUTTON1_CLICKED, NULL);若只想响应鼠标按下动作,可改用
BUTTON1_PRESSED作为掩码,同时将判断条件改为event.bstate & BUTTON1_PRESSED。统一颜色对初始化:将颜色对初始化移到
main函数中,避免重复调用init_pair。比如在start_color()后新增绿色背景的颜色对:start_color(); init_pair(1, COLOR_WHITE, COLOR_BLUE); init_pair(2, COLOR_WHITE, COLOR_GREEN);然后MouseLeftClicked函数中直接使用
COLOR_PAIR(2):void MouseLeftClicked(int x, int y, char *caption) { attron(COLOR_PAIR(2)); mvprintw(y, x, "%s", caption); attroff(COLOR_PAIR(2)); refresh(); }优化刷新逻辑:减少不必要的
refresh()调用,可考虑在主循环末尾统一刷新,避免界面更新冲突。
修改后,鼠标左键点击按钮只会触发一次mvprintw操作,符合预期效果。
内容的提问来源于stack exchange,提问作者Chief Cook
相关产品推荐
相关产品推荐

