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 获得更好的结果。