我已经和C一起工作了一段时间,并且对简单的命令行界面非常熟练。我还有一个使用curses
库的游戏,用于终端应用程序,不仅仅是将文本写入stdout
。但是,我无法确定中途点的位置 - 例如wget
或make
等应用程序可以更新输出的文本(例如wget
蹦蹦跳的下载计和进度条),没有占据整个屏幕。
这种界面是我应该使用的curses
,还是介于两者之间?最好是跨平台的。
答案 0 :(得分:10)
你可以通过打印退格字符'\b'
和原始回车'\r'
(不带换行符)来做一些简单的事情。退格键将光标向后移动一个字符,允许您覆盖输出,回车符将光标移回当前行的开头,允许您覆盖当前行。
以下是进度条的简单示例:
int progress = 0;
while(progress < 100)
{
// Note the carriage return at the start of the string and the lack of a
// newline
printf("\rProgress: %d%%", progress);
fflush(stdout);
// Do some work, and compute the new progress (0-100)
progress = do_some_work();
}
printf("\nDone\n");
请注意,只有在写入实际终端时才应执行此操作(而不是重定向到文件或管道)。您可以使用if(isatty(fileno(stdout)) { ... }
对其进行测试。当然,如果您使用任何其他库,例如curses或ncurses,情况也是如此。
答案 1 :(得分:4)
stdio
和curses
之间是标准的Unix / POSIX termios
库。一个简单的示例程序,可以关闭字符回显并读取一行(注意,没有任何错误检查):
#include <stdio.h>
#include <termios.h>
#include <unistd.h>
void munch_line()
{
int c;
while ((c = getchar()) != EOF && c != '\n')
;
}
int main()
{
int fd;
struct termios tio;
printf("Enter something: ");
tcgetattr(fileno(stdin), &tio);
tio.c_lflag &= ~ECHO;
tcsetattr(fileno(stdin), TCSANOW, &tio);
munch_line();
putchar('\n');
}
在退出程序之前,不要忘记重新开启回声;)
答案 2 :(得分:3)
如果您的终端支持VT100 escape sequences,您可以使用它们来移动光标:
printf("\x1b[%uD", n); /* move cursor n steps to the left */
printf("\x1b[%uC", n); /* move cursor n steps to the right */
printf("\x1b[K"); /* clear line from cursor to the right */
printf("\x1b[1K"); /* clear line from cursor to the left */
printf("\x1b[2K"); /* clear entire line */
一个简单示例(curtest.c
):
#include <stdio.h>
int main(void)
{
printf("ZZZZZZZZZZ");
printf("\x1b[%dD", 10U); /* move cursor 10 steps to the left */
printf("YYYYYYYYY");
printf("\x1b[%dD", 9U); /* move cursor 9 steps to the left */
printf("XXXXXXXX");
printf("\x1b[%dD", 2U); /* move cursor 2 steps to the left */
printf("\x1b[1K"); /* clear line from cursor to the left */
printf("\r\n");
return 0;
}
如果您的终端支持这些转义码,则应打印
mizo@host:~/test> gcc curtest.c
mizo@host:~/test> ./a.out
XYZ
mizo@host:~/test>
Windows命令行没有内置的VT100支持。
答案 3 :(得分:0)
在这里您可以看到与这些答案主题相似的内容。我们当中有些人正在使用简单的回车符。
考虑将xiv
用作增量计数器,size_of_pages
一次为输入或输出显示的数据量。它们都是uint64_t(有点不必要)。 total
是float
。它具有读取整个IO的长度。
if ((((float)(xiv * size_of_pages)/total)*100) >= xnt)
{
xnt = 0.01 + (((float)(xiv * size_of_pages)/total)*100);
printf("\rPercent Done: %.2f%% [", xnt);
float vbc = 0;
kp = 0;
while (vbc < 10)
{
if (kp < (xnt)/10) {
printf("#");
kp += 1;
}
else
{
printf(":");
}
vbc++;
}
cout << "]" << flush;
fflush(stdout);
}