TUI的王者——ncurses.md

ncurses初体验

我们都知道GUI:Graphical User Interface,即图形用户接口。除了GUI以外,还有一种交互接口,那就是TUI,这里的T其实就是text,也就是字符交互界面。也正是我们现在使用的交互界面。在Linux下的TUI交互界面,主要就是由ncurses库实现的。下面就是关于ncurses的一个示例代码:

c 复制代码
#include <ncurses.h>

int main(int argc, const char *argv[])
{
	//使用Ncurses的第一步:初始化ncurses环境
	initscr();
    //输出字符串
    printw("Hello World!");
    //将字符串刷新到屏幕
    refresh();
    //等待按键输入,以达到暂停程序的目的
    getch();
	// 结束 ncurses 模式
	endwin();
	return 0;
}

运行代码之前需要安装一下ncurses库

c 复制代码
sudo apt update
sudo apt install libncurses5-dev -y
c 复制代码
gcc test.c -o test -Wall -lncurses
./test

运行成功以后会发现屏幕上输出了:Hello World!

(按任意键退出程序)

和以往的程序不同,它并不是在命令行下输出的,而是打开了一个界面。程序结束以后又返回到了命令行交互界面上了。

运行ncurses程序需要有以下几个注意事项:

  1. 系统一定安装了ncurses的库;
  2. 所有ncurses程序一般从initscr()函数开始,到endwin()函数结束。
  3. refresh()也是必不可少的函数,官方解释是把窗口内容刷新到界面。实际使用当中,发现只需要执行一次,后续的所有内容都会刷新到界面。反之,你将看不到任何内容。
  4. printw()是用于进行输出的函数,除此以外,ncurses还提供的更多方便的输出函数接口,下面会进行介绍。

ncurses的更详细内容:ncurses(3x) - Linux manual page (man7.org)

ncurses的输出函数

printw()
c 复制代码
int printw(const char *fmt, ...);
addch()
c 复制代码
int addch(char ch);
指定位置输出:
c 复制代码
int mvprintw(int y, int x, const char *fmt, ...);
int mvaddch(int y, int x, chtype ch);

ncurses的窗口

initscr()这个函数的含义是初始化stdscr(即标准屏幕窗口)。这个窗口也是ncurses运行以后的第一个,也是默认的输出窗口。除此以外,你可以创建一个新的窗口:

c 复制代码
WINDOW *newwin(int nlines, int ncols, int begin_y, int begin_x);

参数解释

nlines:窗口的行数,即窗口的高度。

ncols:窗口的列数,即窗口的宽度。

begin_y:窗口在屏幕上的起始行坐标(即窗口的顶部边缘的纵坐标)。

begin_x:窗口在屏幕上的起始列坐标(即窗口的左边缘的横坐标)。

返回值

成功:返回一个指向 WINDOW 结构体的指针,该结构体代表创建的窗口。

失败:返回 NULL,表示创建窗口失败。

示例代码:

c 复制代码
#include <ncurses.h>

int main(int argc, const char *argv[])
{
	//第一步:初始化环境,初始化stdsdc窗口
	initscr();
	//刷新数据
	refresh();
	//创建窗口
	WINDOW *win = newwin(20, 30, 0, 0);
	//绘制窗口边界
	box(win, 0, 0);
	//输出字符串
	mvwaddch(win, 1, 1, '@');
	//刷新显示
	wrefresh(win);
	//等待按键输入,达到阻塞目的
	getch();
	//销毁不使用的窗口
	delwin(win);
	//结束环境
	endwin();
	return 0;
}

注意事项:

  1. 窗口创建完成以后,最终需要调用delwin()销毁
  2. 可以使用box()会在窗口周围绘制出窗口边界,这样有利于识别窗口

ncurses方向按键与非阻塞

方向按键:
c 复制代码
#include <ncurses.h>

int main(int argc, const char *argv[])
{
	initscr();  //初始化scr主窗口界面
	keypad(stdscr, TRUE); //开启特殊按键功能
	curs_set(0);//隐藏光标
	refresh(); //刷新主窗口

	WINDOW *win = newwin(20, 30, 0, 0); //创建窗口win
	box(win, 0, 0); //绘制窗口边界
	wrefresh(win);  //刷新窗口数据

	//循环检测按键
	int ch = 0;
	while('q' != ch){
		ch = getch();
		werase(win);    //清理窗口数据
		box(win, 0, 0); //绘制窗口边界
		switch(ch) {
		case KEY_DOWN:
			mvwprintw(win, 1, 1, "KEY_DOWN");
			break;
		case KEY_UP:
			mvwprintw(win, 1, 1, "KEY_UP");
			break;
		case KEY_LEFT:
			mvwprintw(win, 1, 1, "KEY_LEFT");
			break;
		case KEY_RIGHT:
			mvwprintw(win, 1, 1, "KEY_RIGHT");
			break;
		default:
			mvwprintw(win, 1, 1, "nother key");
		}
		wrefresh(win);  //刷新窗口数据
	}

	delwin(win); //销毁窗口
	endwin(); // 销毁scr主窗口
	return 0;
}

注意事项:

  1. 每次窗口内容更新之前需要调用werase()清理之前遗留的数据。
  2. 每次窗口内容更新之后需要调用wrefresh()把数据更新到屏幕上
开启非阻塞:
c 复制代码
#include <ncurses.h>

int main(int argc, const char *argv[])
{
	initscr();  //初始化scr主窗口界面
	nodelay(stdscr, TRUE);  //开启非阻塞功能
	keypad(stdscr, TRUE); //开启特殊按键功能
	curs_set(0);//隐藏光标
	refresh(); //刷新主窗口

	WINDOW *win = newwin(20, 30, 0, 0); //创建窗口win
	box(win, 0, 0); //绘制窗口边界
	wrefresh(win);  //刷新窗口数据

	//循环检测按键
	int ch = 0;
	while('q' != ch){
		ch = getch();
		//werase(win);    //清理窗口数据
		//box(win, 0, 0); //绘制窗口边界
		//wrefresh(win);  //刷新窗口数据
		switch(ch) {
		case KEY_DOWN:
			mvwprintw(win, 1, 1, "KEY_DOWN ");
			break;
		case KEY_UP:
			mvwprintw(win, 1, 1, "KEY_UP   ");
			break;
		case KEY_LEFT:
			mvwprintw(win, 1, 1, "KEY_LEFT ");
			break;
		case KEY_RIGHT:
			mvwprintw(win, 1, 1, "KEY_RIGHT");
			break;
		default:
			static int a;
			a = a < 10 ? a+1 : 1;
			mvwprintw(win, 2, 1, "          ");
			mvwprintw(win, 2, a, "-");
		}
		napms(40); //暂停40毫秒
		wrefresh(win);  //刷新窗口数据
	}

	delwin(win); //销毁窗口
	endwin(); // 销毁scr主窗口
	return 0;
}
  1. 刷新数据的逻辑变得复杂,需要注意刷新数据函数的特性
  2. 非阻塞以后的更新速度非常快,这将影响后续的游戏运行速度。需要调用napms()调节速度。
相关推荐
AZ996ZA1 天前
自学linux第十九天:Cron定时任务完全指南:从入门到排错
linux·运维·服务器
晚霞的不甘1 天前
Flutter for OpenHarmony 流体气泡模拟器:用物理引擎与粒子系统打造沉浸式交互体验
前端·flutter·ui·前端框架·交互
HIT_Weston1 天前
117、【Ubuntu】【Hugo】首页板块配置:Branch Bundle
linux·运维·ubuntu
Sapphire~1 天前
Linux-14 ubuntu 安装 vscode
linux·vscode·ubuntu
HalvmånEver1 天前
Linux:线程创建与终止下(线程六)
linux·运维·算法
掘根1 天前
【即时通讯系统】环境搭建1——gflags,spdlog
linux·运维·ubuntu
测试工程师成长之路1 天前
AI视觉模型如何重塑UI自动化测试:告别DOM依赖的新时代
人工智能·ui
杜子不疼.1 天前
内网监控工具翻身!Uptime Kuma+cpolar 实现远程运维自由
linux·运维·服务器
范纹杉想快点毕业1 天前
STM32单片机与ZYNQ PS端 中断+状态机+FIFO 综合应用实战文档(初学者版)
linux·数据结构·数据库·算法·mongodb
拾光Ծ1 天前
【Linux】Ext系列文件系统(一):初识文件系统
linux·运维·服务器·硬件架构·ext文件系统