Linux, C, ncurses. Gnome terminal Ubuntu 22.6: printw在同一个实例中打印两次。

huangapple go评论81阅读模式
英文:

Linux, C, ncurses. Gnome terminal Ubuntu 22.6: printw printing twice in one instance

问题

在以下代码示例中,位于MouseLeftClicked函数中的ncurses printw打印了两次,而不是像预期的那样打印一次。我已经在互联网上搜索了类似的问题,但未能找到任何信息。我确信我错过了一些关于ncurses的基础知识,我现在正处于学习的初级阶段。非常感谢任何帮助。TIA

#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));		
}

Linux, C, ncurses. Gnome terminal Ubuntu 22.6: printw在同一个实例中打印两次。

英文:

In the code example below, the ncurses printw located in the MouseLeftClicked function is printing twice instead of once as intended. I've scoured the Internet looking for a similar issue but have been unable to find anything. I'm sure I'm missing something fundamental to ncurses, which I'm in the beginning stages of learning. Any help is greatly appreciated. TIA

#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));		
}

Linux, C, ncurses. Gnome terminal Ubuntu 22.6: printw在同一个实例中打印两次。

答案1

得分: 3

mvprintw在该函数中并不会打印两次。实际上,它确切地在您指定的位置打印文本。之所以不在原始的“Exit”文本位置打印是因为您提供了坐标event.x+1, event.y+1

之所以两者都以绿色绘制是因为您用不同的颜色替换了颜色对1,然后调用了refresh()。原始的“Exit”文本使用了该属性,所以结果是它被重新着色。

如果您只想改变按钮的颜色,您不需要使用mvprintw再次绘制文本。只需更改颜色对并刷新:

init_pair(1, COLOR_WHITE, COLOR_GREEN);
refresh();

进一步阅读:init_pair文档

我强烈建议您使用枚举值或类似的方式为颜色对命名,而不是硬编码魔术数字。这将使代码更可读,减少错误。

示例:

enum ColorPairs {
    kColorPairDefault = 0,  // 特殊默认颜色对
    kColorPairButton,       // 我们按钮的颜色
};

然后,初始设置如下所示:

start_color();          
init_pair(kColorPairButton, COLOR_WHITE, COLOR_BLUE);

attron(COLOR_PAIR(kColorPairButton));
mvprintw(10, 1, " Exit ");
attroff(COLOR_PAIR(kColorPairButton)); 
refresh();

更新如下所示:

init_pair(kColorPairButton, COLOR_WHITE, COLOR_GREEN);
refresh();
英文:

The mvprintw is not printing twice in that function. It is in fact printing text exactly where you told it to. That happens to not be in the same location as the original Exit text because you provided the co-ordinate event.x+1, event.y+1.

The reason why both are drawn in green is because you replaced color pair 1 with a different color and then called refresh(). The original Exit text uses that attribute, so the result is that it's re-colored.

If all you want to do is change the button color, you do not need to draw the text again with mvprintw. Just change the color pair and refresh:

init_pair(1, COLOR_WHITE, COLOR_GREEN);
refresh();

Further reading: init_pair documentation

I would highly recommend you use enum values or similar to name your color pairs, instead of hard-coding magic numbers. That will make the code more readable and less error-prone.

Example:

enum ColorPairs {
kColorPairDefault = 0,  // special default color pair
kColorPairButton,       // color of our button
};

Then, the initial setup looks like this:

    start_color();          
init_pair(kColorPairButton, COLOR_WHITE, COLOR_BLUE);
attron(COLOR_PAIR(kColorPairButton));
mvprintw(10, 1, " Exit ");
attroff(COLOR_PAIR(kColorPairButton)); 
refresh();

And the update looks like this:

    init_pair(kColorPairButton, COLOR_WHITE, COLOR_GREEN);
refresh();

huangapple
  • 本文由 发表于 2023年7月18日 06:48:41
  • 转载请务必保留本文链接:https://go.coder-hub.com/76708533.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定