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

时间:2018-08-17 17:00:40

标签: c++ windows console console-application

我需要打印以控制台一些带有颜色内容的输出。可以在Windows原子上进行吗?在Linux中,有ansi colors支持,并且执行复杂的彩色句子确实非常方便。窗户呢?我可以执行以下操作:

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 color\n");

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

1)使用互斥锁同步所有控制台输出,以便所有消息顺序显示。似乎是针对此类问题的解决方案。

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

因此,我担心的是要获得彩色线条,而其他异步输出不会中断。是否可以在Windows中使用?什么是最佳方法?

1 个答案:

答案 0 :(得分:0)

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

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

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

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

means.mc1 <- rowMeans(mrna.c.1)

这可以像std :: cout一样使用,它将完成您可以使用std :: cout进行的所有操作。另外,您可以编写printf的变体,但要深入遍历std :: arg的深度并不是那么简单。

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

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;
   }
};

想要洋红色输出的线程会做

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

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