ASCII 旋转光标 (TUI) 动画的问题
Problem with ASCII Rotating Cursor (TUI) Animation
我正在尝试创建旋转光标动画。
每次我编译这个时,我总是在最后留下一个(或两个)斜线,退格字符不起作用。我使用了两种方法来做到这一点:睡眠功能和计时定时器,它们的工作方式非常相似,旋转后留下斜线,忽略退格字符。
如果我遗漏任何换行符或操纵符,这将以不同的方式和预期的方式工作。
void spinningCursor() {
for (int i = 1; i <= 100; ++i)
{
cout << "-" << flush;
this_thread::sleep_for(chrono::milliseconds(10));
cout << "\b" << flush;
cout << "\" << flush;
this_thread::sleep_for(chrono::milliseconds(10));
cout << "\b" << flush;
cout << "|" << flush;
this_thread::sleep_for(chrono::milliseconds(10));
cout << "\b" << flush;
cout << "/" << flush;
this_thread::sleep_for(chrono::milliseconds(10));
cout << "\b" << flush;
}
}
或者...
void spinningCursor2() {
for (int i = 0; i < 100; i++) {
cout << "-";
cout.flush();
usleep(10000);
cout << "\b";
cout.flush();
cout << "\";
cout.flush();
usleep(10000);
cout << "\b";
cout.flush();
cout << "|";
cout.flush();
usleep(10000);
cout << "\b";
cout.flush();
cout << "/";
cout.flush();
usleep(10000);
cout << "\b";
cout.flush();
}
}
主要功能...
int main()
{
spinningCursor();
cout <<"\nHello, World!"<< endl;
spinningCursor2();
cout <<"\nHello, World, Again!"<< endl;
return 0;
}
无法保证输出效果,但将其分成几个部分可能会有所帮助。
想法:
#include <algorithm>
#include <chrono>
#include <cstddef>
#include <iostream>
#include <string>
#include <thread>
using namespace std::chrono_literals; // a cumbersome way to be able to write 100ms
// unformatted output of one char, a backspace, flushing and Zzz...
void slow_put(char ch) {
static const auto delay = 100ms;
static const char bs = '\b';
std::cout.write(&ch, 1);
std::cout.write(&bs, 1);
std::cout.flush();
std::this_thread::sleep_for(delay);
}
// newline, but erase the char under it first
void nl() {
std::cout.write(" \n", 2);
}
// proxy ... decorate stuff here (for debugging etc)
void display(char ch) {
slow_put(ch);
}
// enabler to repeat a bunch of sequences
void spinner(const std::string& sequence) {
// execute the display function for one char at a time
std::for_each(sequence.begin(), sequence.end(), display);
}
// example use of the helpers above
void spinningCursorSchema(size_t times) {
static const std::string seq = R"raw(|/-\)raw"; // the pattern to display
while(times--) spinner(seq);
// add more patterns to this schema if wanted
}
int main() {
std::cout << "Spinner: [ ]\b\b";
spinningCursorSchema(100); // run the spinningCursor 100 times
nl(); // erasing newline
}
编辑:简要说明:
对于你调用的每组函数,我觉得可以命名,“do_this()
”或“do_that()
”我把它们放在一个函数中并相应地命名。
这个练习的主要目的不是让我找出代码中的错误,而是提供一个参考框架。当一个人可以说 "your do_this()
function needs this or that..." 或类似的时候,identify/talk about/fix 问题就更容易了。当一切都在一个大代码块中时,每个阅读它的人都需要从零开始。一个名字清晰的函数(或者像我上面那样用注释来弥补糟糕的命名,"proxy")并且只有几行代码可以被没有太多关于更大问题背景知识的人审查。
简而言之,我把你专门为做一件事而创建的代码分解成几个函数,我用这些函数重建了类似于你最初想法的东西。通过这样做,我更容易看到缺陷,谈论设计决策。如果一个 2-4 行的功能可以被 10000 人审查并且他们没有发现问题,那么该功能本身就是问题的可能性很小。通过构建具有明确目的的小功能块,每个人都可以更容易地进行错误查找,而不仅仅是深入参与您正在解决的特定问题的人。
我现在看到我使用了来自 <algorithm>
的函数模板,它可能不熟悉:std::for_each
。在这种情况下,它可以替换为:
for(char ch : sequence) display(ch);
想想就更清楚了
如果这不是您要的概述,请评论并指出您想要解释的部分,我会再试一次
退格字符实际上并没有删除前一个字符,它所做的只是将光标本身向后移动一个 "space"。它是退格键 后跟 的组合,通过写入另一个字符来覆盖或 "delete" 字符。
此外,退格键只退到当前行的开头。打印换行符后,您无法返回 "up" 带有退格键的行。
在 Windows 上,您可以使用 Windows console functions, and on POSIX systems (like Linux or macOS) maybe VT100 escape codes 获得更好的结果。
我正在尝试创建旋转光标动画。
每次我编译这个时,我总是在最后留下一个(或两个)斜线,退格字符不起作用。我使用了两种方法来做到这一点:睡眠功能和计时定时器,它们的工作方式非常相似,旋转后留下斜线,忽略退格字符。
如果我遗漏任何换行符或操纵符,这将以不同的方式和预期的方式工作。
void spinningCursor() {
for (int i = 1; i <= 100; ++i)
{
cout << "-" << flush;
this_thread::sleep_for(chrono::milliseconds(10));
cout << "\b" << flush;
cout << "\" << flush;
this_thread::sleep_for(chrono::milliseconds(10));
cout << "\b" << flush;
cout << "|" << flush;
this_thread::sleep_for(chrono::milliseconds(10));
cout << "\b" << flush;
cout << "/" << flush;
this_thread::sleep_for(chrono::milliseconds(10));
cout << "\b" << flush;
}
}
或者...
void spinningCursor2() {
for (int i = 0; i < 100; i++) {
cout << "-";
cout.flush();
usleep(10000);
cout << "\b";
cout.flush();
cout << "\";
cout.flush();
usleep(10000);
cout << "\b";
cout.flush();
cout << "|";
cout.flush();
usleep(10000);
cout << "\b";
cout.flush();
cout << "/";
cout.flush();
usleep(10000);
cout << "\b";
cout.flush();
}
}
主要功能...
int main()
{
spinningCursor();
cout <<"\nHello, World!"<< endl;
spinningCursor2();
cout <<"\nHello, World, Again!"<< endl;
return 0;
}
无法保证输出效果,但将其分成几个部分可能会有所帮助。
想法:
#include <algorithm>
#include <chrono>
#include <cstddef>
#include <iostream>
#include <string>
#include <thread>
using namespace std::chrono_literals; // a cumbersome way to be able to write 100ms
// unformatted output of one char, a backspace, flushing and Zzz...
void slow_put(char ch) {
static const auto delay = 100ms;
static const char bs = '\b';
std::cout.write(&ch, 1);
std::cout.write(&bs, 1);
std::cout.flush();
std::this_thread::sleep_for(delay);
}
// newline, but erase the char under it first
void nl() {
std::cout.write(" \n", 2);
}
// proxy ... decorate stuff here (for debugging etc)
void display(char ch) {
slow_put(ch);
}
// enabler to repeat a bunch of sequences
void spinner(const std::string& sequence) {
// execute the display function for one char at a time
std::for_each(sequence.begin(), sequence.end(), display);
}
// example use of the helpers above
void spinningCursorSchema(size_t times) {
static const std::string seq = R"raw(|/-\)raw"; // the pattern to display
while(times--) spinner(seq);
// add more patterns to this schema if wanted
}
int main() {
std::cout << "Spinner: [ ]\b\b";
spinningCursorSchema(100); // run the spinningCursor 100 times
nl(); // erasing newline
}
编辑:简要说明:
对于你调用的每组函数,我觉得可以命名,“do_this()
”或“do_that()
”我把它们放在一个函数中并相应地命名。
这个练习的主要目的不是让我找出代码中的错误,而是提供一个参考框架。当一个人可以说 "your do_this()
function needs this or that..." 或类似的时候,identify/talk about/fix 问题就更容易了。当一切都在一个大代码块中时,每个阅读它的人都需要从零开始。一个名字清晰的函数(或者像我上面那样用注释来弥补糟糕的命名,"proxy")并且只有几行代码可以被没有太多关于更大问题背景知识的人审查。
简而言之,我把你专门为做一件事而创建的代码分解成几个函数,我用这些函数重建了类似于你最初想法的东西。通过这样做,我更容易看到缺陷,谈论设计决策。如果一个 2-4 行的功能可以被 10000 人审查并且他们没有发现问题,那么该功能本身就是问题的可能性很小。通过构建具有明确目的的小功能块,每个人都可以更容易地进行错误查找,而不仅仅是深入参与您正在解决的特定问题的人。
我现在看到我使用了来自 <algorithm>
的函数模板,它可能不熟悉:std::for_each
。在这种情况下,它可以替换为:
for(char ch : sequence) display(ch);
想想就更清楚了
如果这不是您要的概述,请评论并指出您想要解释的部分,我会再试一次
退格字符实际上并没有删除前一个字符,它所做的只是将光标本身向后移动一个 "space"。它是退格键 后跟 的组合,通过写入另一个字符来覆盖或 "delete" 字符。
此外,退格键只退到当前行的开头。打印换行符后,您无法返回 "up" 带有退格键的行。
在 Windows 上,您可以使用 Windows console functions, and on POSIX systems (like Linux or macOS) maybe VT100 escape codes 获得更好的结果。