以原子方式将彩色文本写入 Windows 中的控制台



>我需要打印以控制台一些带有颜色内容的输出。是否可以原子地在窗口中进行?在Linux中,有ansi颜色支持,做复杂的彩色句子真的非常方便。窗户呢?我可以执行以下操作:

HANDLE hConsole = GetStdHandle(STD_OUTPUT_HANDLE);
printf(" this is how it starts ");
SetConsoleTextAttribute(hConsole, 10);
printf("YES, it should be green ");
SetConsoleTextAttribute(hConsole, 0);
printf("back to standard colorn");

在我看来,在异步应用程序中,这 3 个 printf 不会在控制台中的同一行打印文本。我想到了2个解决方案:

1( 使用互斥锁同步所有控制台输出,以便所有消息按顺序显示。对于此类问题,似乎是一个矫枉过正的解决方案。

2(使用某种方法停止控制台输出一段时间,打印彩色线条,然后再次开始输出。

因此,我担心的是获得其他异步输出没有中断的彩色线。在窗口中是否可能,最好的方法是什么?

正如@eryksun所说,使用 WriteConsoleOutput 而不是 printf/std::cout。

这与任何图形应用程序相同。 只有一个线程完成所有写入。 它有一个包含字符串和属性列表的队列。 当线程希望打印某些内容时,它会将字符串和相关属性推送到队列中。 在打印之前,写入线程设置属性,然后打印字符串。

您需要实现自己的线程安全队列。 我的通常是低音量输出,所以我使用带有uint8_t计数器和原子标记的 256 数组。 没有边界检查:uint8_t在 255 之后换行为 0。 循环队列工作得很好。

您可以创建一个非常简单的类来进行编写。 我通常使用这样的东西。 涂鸦者是对屏幕进行书写的类

class COut : public std::ostringstream
{
Scribbler* writer;
WORD attr;
public:
COut(WORD in_attr)
{
attr = in_attr;
writer = Scribbler::Me();
}
COut& operator << (std::ostream&(*f)(std::ostream&))
{
if (f == std::endl)
{
*this << "n";
writer->Push(attr, str());
str("");
}
else
{
*this << f;
}
return *this;
}
template <typename TT>
inline COut& operator << (const TT& t)
{
(*(std::ostringstream*) this) << t;
return *this;
}
};

这可以像 std::cout 一样使用,它将完成您可以使用 std::cout 执行的所有操作。 或者,你可以写一个printf的变体,但当你进入到处传递std::arg的深度时,它就不是那么简单了。

想要黄色输出的线程会做类似的事情

COut yout(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_INTENSITY);
...
yout << "Yellow, yellow dirty fellow" << std::hex << std::setfill('0') << std::setw(4) << 25 << std::endl;

想要洋红色输出的线程就可以了

COut mout(FOREGROUND_RED | FOREGROUND_BLUE | FOREGROUND_INTENSITY);
...
mout << ... << std::endl;

在发布 std::endl 之前,不会打印任何内容。 你可以通过不同的线程使用SetConsoleWindowInfo写入屏幕的不同可滚动部分来获得非常有创意。 只要只有一个线程进行写入,它就会起作用。 所有其他线程只是告诉它在哪里写入输出及其颜色属性。

最新更新