ASCII旋转光标(TUI)动画的问题

问题描述 投票:0回答:1

我正在尝试创建旋转光标动画的事情。

每次编译的时候,我总是在最后留下一个(或两个)斜线,而且退格字符也不起作用。我用了两种方法:睡眠功能和计时功能,它们的工作原理非常相似,在旋转后留下一个斜线,忽略了退格字符。

如果我省略任何换行字符或操作符,这个工作方式和预期不同。

    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; 
} 
c++ command-line-interface progress-bar tui
1个回答
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()" 我把它们放在一个函数中,并给它们起了相应的名字。

这个练习的目的主要不是让我找到你代码中的错误,而是提供一个参考框架。当一个人可以说 "你的... "的时候,就更容易发现问题并进行修复。do_this() 功能需要 这个 ... "或类似的。当所有的东西都在一个大的代码块中时,每个人阅读它都需要从零开始。一个有明确名称的函数(或者像我上面做的那样用注释来弥补糟糕的命名,"proxy")和只有几行代码的函数可以被每个人审查,而不需要对更大的问题有太多的背景知识。

简而言之,我把你那段专门为做一件事而创建的代码分解成了几个函数,我用这些函数重建了类似于你最初想法的东西。通过这样做,我更容易看到缺陷,谈论设计决策。如果一个2-4行的函数可以被10000人审查,而他们没有发现问题,那么这个函数是问题(本身)的可能性很小。通过构建具有明确目的的小函数块,bghunting变得对每个人来说都更可用,而不仅仅是深深卷入你要解决的特定问题的人。

我现在看到,我使用了一个函数模板,从 <algorithm> 可能不熟悉的。std::for_each. 在这种情况下,它可以被替换为。

for(char ch : sequence) display(ch);

仔细想想,那就更清楚了。 Come to think of it, that's even clearer.

如果这不是你想要的概述,请评论并指出你希望得到解释的部分,我将再次尝试。


0
投票

退格字符实际上并没有删除前一个字符,它所做的只是将光标本身向后移动一个 "空格"。这就是退格键的组合 随后 通过写另一个字符来覆盖或 "删除 "该字符。

另外,退格键只能到当前行的开头。一旦你打印了一个新行,你就不能用退格键回到 "上 "一行。

在Windows上,你可以通过使用 窗口控制台功能在POSIX系统上(如Linux或macOS),也许是 VT100逃生密码.

© www.soinside.com 2019 - 2024. All rights reserved.