清空 C++ 中的控制台

3
我正在尝试在C++中清除控制台。我知道打印多个换行符是一种不好的做法,因为它可能会很慢,并且不能保证完全清除控制台窗口,但我已经研究了多种选项,除了system("cls")之外几乎没有其他解决方案,而这甚至是更糟糕的选择。
实际上,我使用了cout << string(100, '\n');这一行,但当我尝试运行程序时,我得到了一个几乎无法识别的错误。 error C2679: binary '<<' : no operator found which takes a right-hand operand of type 'std::basic_string<_Elem,_Traits,_Ax>' (or there is no acceptable conversion) 我也进行了调查,并发现大多数解释对于我这个初学者来说太复杂了,或者与我的问题完全无关。
我的问题是:(1)是否有修复此错误的方法?(2)除了打印100个换行符之外,是否有更好的跨平台清除控制台的方法?
我还听说过Console.clear(),但我不确定它是否跨平台。从我所看到的,它更像是Windows命令。我还听说过库,我愿意研究和使用它,直到我在某个地方读到不建议将我熟悉的函数与curses库函数组合使用。
提前感谢!

请查看此处:https://dev59.com/PXVC5IYBdhLWcg3woSxW,以获取您第二个问题的答案。 - NickLH
清屏是您想要的唯一非电传打字机行为吗?还是您更普遍地想要curses行为(知道屏幕大小,定位光标,覆盖已经写入的文本等等)?如果只是清屏,我建议让用户自己处理,因为在许多终端程序中都有相应的按键。如果您没有充分理由向我的滚动缓冲区写入一百个换行符...我个人会感到很烦恼! - HostileFork says dont trust SE
很多在终端提示符下有效的快捷键,例如xterm中的Ctrl-L,在运行控制台I/O程序时将无法使用。但是在运行过程中,如果我想清除我的xterm,我可以说“Ctrl-Shift-X”,在Mac上是Command-K。(这实际上也清除了屏幕和滚动缓冲区。)但这并不是坏事...如果您几乎是一个普通的控制台I/O程序,您应该将清除决策留给终端用户--这是Unix工具箱模型中的期望,并且只有在您有非常充分的理由时才应打破它... - HostileFork says dont trust SE
如果这只是一项C++学习练习,而且没有其他人会运行,那么你做这件事的方式并不重要-"无论怎样都可以"。但如果你正在编写游戏并进行风格化的文本处理,我建议您使用跨平台工具包(如Qt),并完全控制富文本小部件(甚至是webkit小部件)... 这将为您提供一个相当支持的fat api (http://doc.qt.nokia.com/latest/qtextedit.html)。 但是,如果要更加“meta”,则通过针对HTML5 / JavaScript来定位风格化文本游戏,您将获得更广泛的受众... - HostileFork says dont trust SE
@HostileFork 确实。感谢您的帮助。这更像是一个学习练习,一件有趣的事情,我并不打算公开发布。在某个时候,我会查看您提到的那些工具包,也许等我更有经验了再去看看。再次感谢! - Abluescarab
显示剩余7条评论
3个回答

3
以猜测的方式,你当前的问题可能是缺少#include <string>
处理屏幕最具可移植性的方式可能是通过ncurses。它被包含在POSIX和大多数类POSIX系统中,并且作为库在其他大多数系统(例如Windows)中也可用。
编辑:值得一提的是,在Windows上清除屏幕不需要接近100行代码。
#include <windows.h>

void clear_screen(char fill = ' ') { 
    COORD tl = {0,0};
    CONSOLE_SCREEN_BUFFER_INFO s;
    HANDLE console = GetStdHandle(STD_OUTPUT_HANDLE);   
    GetConsoleScreenBufferInfo(console, &s);
    DWORD written, cells = s.dwSize.X * s.dwSize.Y;
    FillConsoleOutputCharacter(console, fill, cells, tl, &written);
    FillConsoleOutputAttribute(console, s.wAttributes, cells, tl, &written);
    SetConsoleCursorPosition(console, tl);
}

#ifdef TEST
int main(){ 
    clear_screen();
    return 0;
}
#endif

我要先说一下,这段代码比我想象的还要冗长——但它不到十行,更别提一百行了。即使是在微软知识库中的版本,实际上也不到40行——其中很多是空白或注释。

然而公正地说,我觉得有必要承认,直接编写汇编语言代码到硬件(或使用BIOS)确实会变得更短。


谢谢,那个解决方案有效,尽管我知道这是一种不好的做法,而且我个人认为它看起来相当不吸引人。我假设我应该包括pcurses和ncurses的Windows和Linux库,并使用下面提到的#if方法来检查操作系统是Windows还是Linux? - Abluescarab
1
@Abluescarab:我通常不使用#if。相反,我将平台特定的代码分离到几个特定的文件中,并在makefile中处理差异。 - Jerry Coffin
我在C++方面非常没有经验,我是一名高中学生,刚加入了一个C++课程来学习更多知识,所以我不太了解如何拆分特定于平台的代码并处理makefile中的差异。 我不想打扰你去解释它,除非你觉得有必要,因为它可能比我最初希望的要复杂一些。如果有一个简单、不复杂的方法可以清除控制台而不需要这些额外的麻烦,那就太好了。 - Abluescarab
@Abluescarab:一般的想法非常简单:为Windows准备一个文件,为Linux准备另一个文件,为MacOS准备第三个文件。在为每个操作系统构建时,只需编译该操作系统的文件即可。例如Curses将处理该部分,因此您可以为任何(支持的)目标执行相同的工作。 - Jerry Coffin

3

关于您的错误... 您需要...

#include <iostream> 
#include <string>

using namespace std;

如果您只使用Windows,请使用Windows控制台API。 如果您使用的是Linux\Unix终端,请使用转义码。 可以使用#if来选择两种方法之间的一种。
在Linux\Unix上,使用以如下方式定义的写函数:
write(1,"\E[H\E[2J",7); // we use ANSI escape sequences here.

这里是微软页面,解释如何操作:

http://support.microsoft.com/kb/99261

微软在控制台API中使用的非常糟糕,总是让我很生气 :) 为什么要100行代码才能清除一个屏幕? :)
现在,如果...您应该创建一个clearscreen.h文件和一个clearscreen.cpp文件。
在clearscreen.h中,我们只需要放置我们的函数。
 void clearconsole();

在 clearscreen.cpp 中,我们放置了适用于两个操作系统的代码。
#ifdef _WIN32 || _WIN64

    #include <windows.h>

    void clearconsole()
    {
        ...
        // 100 lines of codes copied from microsoft article
    }

#else

    #include <unistd.h>

    void clearconsole()
    {
        write(1,"\E[H\E[2J",7);
    }

#endif

谢谢你的回答!这非常有价值,虽然我肯定需要查一下 ANSI 转义码的含义。目前为止,我相信我正在使用一些特定于 Windows 的方法,所以最终可能会使程序仅限于 Windows。不过,如果可以的话,我能否请您详细说明或提供如何使用 #if 方法的链接?再次感谢!编辑:啊,找到了!谢谢! - Abluescarab
非常感谢您不断更新答案,让它变得越来越具体! :D 我一定会尝试那个方法,并很有可能采用它。 - Abluescarab
1
ncurses 抽象出转义序列,使其能在任何终端中工作。 - Martin York
如果你在使用微软平台,为什么不直接使用 system("cls") 呢?它可以完成任务。 - viraj
对于ncurses来说是正确的,但如果只需要清除屏幕,为什么我们要引用外部库,而不是只写一行代码呢?问题随之而来的是Windows操作系统。虽然有ncurses的Windows端口,但是真的需要包含一个庞大而复杂的库,寻找正确的32位或64位版本,在我的程序中包含GPL许可证只是为了清除屏幕吗? - Salvatore Previti
显示剩余5条评论

1

我知道这是一个完全的过时回复。但是我想出了一个非常好的解决方案,希望在将来有人遇到这个问题时可以分享一下。

void clearConsole() {
#ifdef _WIN32
#include <iostream>
    static const char* CSI = "\33[";
    printf("%s%c%s%c", CSI, 'H', CSI, '2J');

#else
#include <unistd.h>
    write(1, "\E[H\E[2J", 7);
#endif
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接