Вывод цветного текста в консоль Windows в С++
При выводе текстовой информации в консоль, может возникнуть потребность изменить цвет или фон выводимого текста, чтобы привлечь к несу внимание пользователя. Обычно это важные сообщения или сообщения об ошибках.
Сегодня мы рассмотрим вывод цветного текста в консоль Windows в C++.
В прошлой статье - https://blog.altuninvv.ru/яп/c/создаем-пустой-проект-c-в-консоли-cmd мы рассмотрели создание пустого проекта. Я подразумеваю что вы уже его создали, и мы продолжаем работать с этим проектом.
Настраиваем терминал в VSCode
Прежде чем мы продолжим, нам нужно будет настроить терминал в VSCode.
По умолчанию терминал VSCode не настроен на корректное отображение всех 256 цветов, поэтому нам потребуется дополнительная настройка.
Нажмем F1 и введем:
settingsВыберем пункт:
Preferences: Open user Settings (JSON)В конец файла, перед
}Добавим строки:
"terminal.integrated.minimumContrastRatio": 1,
"terminal.integrated.env.windows": { "TERM": "xterm-256color" },
"terminal.integrated.env.linux": { "TERM": "xterm-256color" },
"terminal.integrated.gpuAcceleration": "off",
"terminal.integrated.windowsEnableConpty": false,Убедитесь, что в конце предыдущей строки, перед строкой:
"terminal.integrated.minimumContrastRatio": 1,Есть запятая, это важно!
Сохраним файл.
Обратите внимание! Несмотря на все эти настройки, у вас могут возникать проблемы с отображением цветов. В этом случае я рекомендую использовать отдельно запущенную консоль cmd для тестирования.
После изменения настроек обязательно закройте все окна VSCode, чтобы его полностью перезапустить!
Создаем новый класс ColorConsole
Для изменения цвета текста и фона в консоли создадим класс ColorConsole.
Обратите внимание, имена файлов должны быть в нижнем регистре! Всегда задавайте имена файлов таким образом, и у вас не возникнет проблем при портировании вашего кода в Linux!
Заголовок:
#ifndef COLORCONSOLE_H
#define COLORCONSOLE_H
#include <windows.h>
class ColorConsole
{
public:
static const int BLACK = 0;
static const int DARK_BLUE = 1;
static const int DARK_GREEN = 2;
static const int DARK_CYAN = 3;
static const int DARK_RED = 4;
static const int DARK_MAGENTA = 5;
static const int DARK_YELLOW = 6;
static const int LIGHT_GRAY = 7;
static const int DARK_GRAY = 8;
static const int LIGHT_BLUE = 9;
static const int LIGHT_GREEN = 10;
static const int LIGHT_CYAN = 11;
static const int LIGHT_RED = 12;
static const int LIGHT_MAGENTA = 13;
static const int LIGHT_YELLOW = 14;
static const int WHITE = 15;
ColorConsole();
~ColorConsole();
static void init();
static HANDLE __console_stdout_handle;
static HANDLE __console_stderr_handle;
static void setConsStdOutColor(int color, int bgColor = 0);
static void setConsStdErrColor(int color, int bgColor = 0);
};
#endifРеализация:
#include "colorconsole.h"
ColorConsole::ColorConsole()
{
}
ColorConsole::~ColorConsole()
{
}
HANDLE ColorConsole::__console_stdout_handle;
HANDLE ColorConsole::__console_stderr_handle;
void ColorConsole::init()
{
ColorConsole::__console_stdout_handle = GetStdHandle(STD_OUTPUT_HANDLE);
ColorConsole::__console_stderr_handle = GetStdHandle(STD_ERROR_HANDLE);
}
void ColorConsole::setConsStdOutColor(int color, int bgColor)
{
SetConsoleTextAttribute(ColorConsole::__console_stdout_handle, color + (bgColor*16));
}
void ColorConsole::setConsStdErrColor(int color, int bgColor)
{
SetConsoleTextAttribute(ColorConsole::__console_stderr_handle, color + (bgColor*16));
}В файл CMakeLists.txt после:
main.cppДобавим строки:
colorconsole.h
colorconsole.cppУ нас получится:
cmake_minimum_required(VERSION 3.16)
project(colorconsole VERSION 0.1 LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
add_executable(colorconsole
main.cpp
colorconsole.h
colorconsole.cpp
)
include(GNUInstallDirs)В файл main.cpp добавим:
#include "colorconsole.h"Изменим функцию main():
int main(int argc, char *argv[])
{
ColorConsole::init();
ColorConsole::setConsStdOutColor(4);
std::cout << "Hello world";
return 0;
}Запустим:
Обратите внимание, у нас не только строка выводимая программой стала красной но и все последующие строки будут красными. Это продлится до перезапуска консоли или до запуска команды.
Чтобы сбросить цвет в консоли PowerShell нужно ввести:
clearВ консоли cmd нужно ввести:
colorДавайте добавим еще один статический метод, для сброса цвета к настройкам по умолчанию.
В заголовок класса ColorConsole добавим:
static void setConsStdOutDefColor();
static void setConsStdErrDefColor();Реализация:
void ColorConsole::setConsStdOutDefColor()
{
SetConsoleTextAttribute(ColorConsole::__console_stdout_handle, 7);
}
void ColorConsole::setConsStdErrDefColor()
{
SetConsoleTextAttribute(ColorConsole::__console_stderr_handle, 7);
}В файл main.cpp добавим перед строкой:
return 0;Строку:
ColorConsole::setConsStdOutDefColor();Запустим:
Теперь у нас при выходе из программы цвета восстанавливаются.
Рассмотрим подробнее, как это работает.
Работа с цветом в консоли
Для установки цвета используется вызов системной функции Windows:
WINBASEAPI WINBOOL WINAPI SetConsoleTextAttribute(HANDLE console_output, WORD attributes);она объявлена в заголовочном файле:
#include <windows.h>Первым параметром функция принимает дескриптор устройства вывода. Это могут быть устройства стандартного вывода (stdout) и устройство вывода ошибок (stderr).
При этом дескриптор не является указателем, если мы попробуем вывести его значение:
std::cout << ColorConsole::__console_stdout_handle << "\n";
std::cout << ColorConsole::__console_stderr_handle << "\n";То получим результат:
0x54
0x58Эти значения всегда будут разными!
При выводе на консоль эти дескрипторы указывают на одно и тоже устройство вывода – виртуальную консоль, поэтому даже если мы запустим код:
ColorConsole::setConsStdErrColor(ColorConsole::DARK_RED);
ColorConsole::setConsStdOutColor(ColorConsole::DARK_GREEN);
std::cout << "-== stdout ==-\n";
std::cerr << "-== !error! ==-\n";И запустим, то вместо ожидаемого красного цвета получим две зеленые строки.
Поэтому если нам нужно выводить ошибки красным, нужно перед этим выставить цвет консоли:
ColorConsole::setConsStdOutColor(ColorConsole::DARK_GREEN);
std::cout << "-== stdout ==-\n";
ColorConsole::setConsStdErrColor(ColorConsole::DARK_RED);
std::cerr << "-== !error! ==-\n";Поэтому, для вывода сообщений разным цветом вам потребуется написать свои функции устанавливающие и сбрасывающие цвета, перед выводом сообщений в коносль!
Выводим палитру цветов
Какие бывают цвета? Стандартная консоль способна отобразить 256 цветов.
В классе ColorConsole мы уже описали базовые:
static const int BLACK = 0;
static const int DARK_BLUE = 1;
static const int DARK_GREEN = 2;
static const int DARK_CYAN = 3;
static const int DARK_RED = 4;
static const int DARK_MAGENTA = 5;
static const int DARK_YELLOW = 6;
static const int LIGHT_GRAY = 7;
static const int DARK_GRAY = 8;
static const int LIGHT_BLUE = 9;
static const int LIGHT_GREEN = 10;
static const int LIGHT_CYAN = 11;
static const int LIGHT_RED = 12;
static const int LIGHT_MAGENTA = 13;
static const int LIGHT_YELLOW = 14;
static const int WHITE = 15;Остальные цвета получаются наложением на фон этого цвета текста другого цвета.
В main.cpp добавим код:
ColorConsole::setConsStdOutDefColor();
for (int i = 0; i < 256; i++)
{
if ((i % 16 == 0) && (i != 0))
{
ColorConsole::setConsStdOutDefColor();
std::cout << std::endl;
}
ColorConsole::setConsStdOutColor(i);
printf("[%03d]", i);
}
ColorConsole::setConsStdOutDefColor();Запустим.
Выводим пустые строки
При форматировании вывода вам может понадобится вставить пустую строку черного цвета. Чтобы не устанавливать каждый раз цвет вручную, добавим новый статический метод класса ColorConsole:
Заголовок:
static void emptyLine();Реализация:
void ColorConsole::emptyLine()
{
ColorConsole::setConsStdErrDefColor();
std::cout << std::endl;
}Так же добавим в colorconsole.cpp:
#include <iostream>Теперь мы можем изменить код:
ColorConsole::emptyLine();
for (int i = 0; i < 256; i++)
{
if ((i % 16 == 0) && (i != 0)) {
ColorConsole::emptyLine();
}
ColorConsole::setConsStdOutColor(i);
printf("[%03d]",i);
}
ColorConsole::emptyLine();Запустим, результат не изменится.
Обратите внимание на пустые ячейки - это места, где цвет фона и текста одинаков!
Значение цвета можно высчитать и самому, для это возьмем цвет фона, например, светло-малиновый (Magenta) и цвет текста желтый. Судя по таблице это цвет с номером 222.
Мы уже определили константы для базовых цветов, так что давайте вычислим:
LIGHT_YELLOW + ( LIGHT_MAGENTA * 16 ) = 14 + (13*16) = 14 + 208 = 222Если мы сейчас добавим код в main.cpp:
ColorConsole::emptyLine();
ColorConsole::emptyLine();
ColorConsole::setConsStdOutColor(222);
std::cout << "[ 222 ]";
ColorConsole::emptyLine();
ColorConsole::emptyLine();и запустим, то получим:
Мы также можем добавить флаг России:
ColorConsole::emptyLine();
ColorConsole::emptyLine();
ColorConsole::setConsStdOutColor(ColorConsole::WHITE,ColorConsole::WHITE);
printf("%10s"," ");
ColorConsole::emptyLine();
ColorConsole::setConsStdOutColor(ColorConsole::WHITE,ColorConsole::DARK_BLUE);
printf("%10s"," RUSSIA ");
ColorConsole::emptyLine();
ColorConsole::setConsStdOutColor(ColorConsole::DARK_RED,ColorConsole::DARK_RED);
printf("%10s"," ");
ColorConsole::emptyLine();
ColorConsole::emptyLine();Результат:
Заключение
Сегодня мы рассмотрели вывод цветного текста в консоль в C++:
Настроили консоль VSCode для корректного отображения цветов;
Добавили новый класс ColorConsole;
Рассмотрели особенности изменения цвета в консоли Windows;
Вывели таблицу со всеми доступными цветами;
Рассмотрели по какой формуле высчитывается номер цвета;
Вывели флаг России;
В следующей статье мы преобразуем наш класс в библиотеку C++ с помощью CMake.
Добавить комментарий