Четверг, 21.08.2025 19:00

Вывод цветного текста в консоль на С++

Вывод цветного текста в консоль 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.

Категория C++
Теги Cpp CMAKE

Добавить комментарий

Простой текст

  • HTML-теги не обрабатываются и показываются как обычный текст
  • Строки и абзацы переносятся автоматически.
  • Адреса веб-страниц и email-адреса преобразовываются в ссылки автоматически.
Просмотров: 726