파이썬에서 콘솔 글자색 지정하기 (윈도우즈)

이 포스트에서는 파이썬에서 윈도우의 명령 프롬프트 콘솔의 글자색을 지정하는 방법에 대해 설명합니다.

이미 파이썬에서 콘솔 글자색 및 효과 지정하기 (리눅스) 포스트에서 콘솔 글자색 지정 방법에 대해 포스팅했지만, 이 방법은 윈도우즈의 명령 프롬프트에서는 사용할 수 없습니다. 대신 윈도우즈의 콘솔 관련 API에 내장된 SetConsoleTextAttribute() 함수에 접근하는 방법을 씁니다.

일단, 코드를 봅시다.

STD_INPUT_HANDLE   = -10
STD_OUTPUT_HANDLE  = -11
STD_ERROR_HANDLE   = -12

FOREGROUND_BLACK     = 0x00
FOREGROUND_BLUE      = 0x01 # text color contains blue.
FOREGROUND_GREEN     = 0x02 # text color contains green.
FOREGROUND_RED       = 0x04 # text color contains red.
FOREGROUND_INTENSITY = 0x08 # text color is intensified.
BACKGROUND_BLUE      = 0x10 # background color contains blue.
BACKGROUND_GREEN     = 0x20 # background color contains green.
BACKGROUND_RED       = 0x40 # background color contains red.
BACKGROUND_INTENSITY = 0x80 # background color is intensified.

import ctypes

std_out_handle = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)

def set_color(color, handle=std_out_handle):
    bool = ctypes.windll.kernel32.SetConsoleTextAttribute(handle, color)
    return bool

for i in range(0, 16):
	set_color(i)
	print("Hello, world!")

set_color(FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE)

먼저 API 사용을 위한 변수 선언을 합니다. 색상 번호 체계가 리눅스 콘솔 때와는 다른데, 1번이 파랑이고 2번이 초록, 4번이 빨강입니다. 청록은 3번(1+2), 보라는 5번(1+4), 노랑은 6번(2+4), 하양은 7번(1+2+4)입니다. 여기서 +8을 하면 그 색이 밝아집니다. 그리고 글자 배경색은 그 색상 번호에서 ×16을 한 값을 더합니다. 예를 들어, 파란 바탕에 밝은 흰색은 (1×16)+15 해서 31번이 됩니다.

15번 줄에서 API 사용을 위해 ctypes 모듈을 로드하고 17번 줄에서는 API에 접근해 함수를 사용하기 위한 핸들 값을 얻습니다. 그리고 19번 줄부터 21번 줄까지는 API 함수를 사용하기 좋게 함수 선언을 하는 블록입니다.

21번 줄부터 23번 줄까지는 이를 실험해 보기 위한 반복문입니다. 0번부터 15번까지가 차례로 설정됩니다. 글자색이 검정-파랑-초록-청록-빨강-보라-황토-은회색 순으로 색이 입혀지고 앞의 8색이 더 밝아진 색으로 또 차례로 입혀집니다.
그리고 25번 줄에서 글자 색을 은회색으로 원상복구하고 끝냅니다. FOREGROUND_RED, FOREGROUND_GREEN, FOREGROUND_BLUE 사이에 있는 세로막대(|)는 논리합을 나타내는 논리연산자입니다. 7을 대신 써도 효과는 같습니다.

실행 결과는 다음과 같습니다.

명령 프롬프트 색 테스트

이렇게 차례대로 색이 입혀져서 표시됨을 알 수 있습니다. 명령 실행줄과 파란색 Hello, world! 사이의 줄이 비어 있는 것처럼 보이는데 이는 비어 있는 게 아니라 글자색과 배경색이 똑같이 검정이어서 보이지 않는 것입니다.

[2019. 01. 19. 추가]
한 줄에 둘 이상의 글자색이 나오게 하려면 아래와 같이 sys 모듈을 불러서 줄 중간에 색이 바뀔 때 sys.stdout.flush() 문을 써 주면 됩니다.

STD_INPUT_HANDLE   = -10
STD_OUTPUT_HANDLE  = -11
STD_ERROR_HANDLE   = -12
 
FOREGROUND_BLACK     = 0x00
FOREGROUND_BLUE      = 0x01 # text color contains blue.
FOREGROUND_GREEN     = 0x02 # text color contains green.
FOREGROUND_RED       = 0x04 # text color contains red.
FOREGROUND_INTENSITY = 0x08 # text color is intensified.
BACKGROUND_BLUE      = 0x10 # background color contains blue.
BACKGROUND_GREEN     = 0x20 # background color contains green.
BACKGROUND_RED       = 0x40 # background color contains red.
BACKGROUND_INTENSITY = 0x80 # background color is intensified.
 
import ctypes
import sys

std_out_handle = ctypes.windll.kernel32.GetStdHandle(STD_OUTPUT_HANDLE)

def set_color(color, handle=std_out_handle):
    bool = ctypes.windll.kernel32.SetConsoleTextAttribute(handle, color)
    return bool

textes = [
    '1|궁  예|누구인가? 지금 누가 기침소리를 내었어?',
    '1|궁  예|누가 기침소리를 내었는가 말이야?!',
    '2|관료 1|시, 시... 신이옵니다, 폐하. (콜록콜록)',
    '1|궁  예|기침소리 그라샤★',
    '2|관료 1|?',
    '1|궁  예|요를레이 요를레이 요를레이히☆',
    '2|관료 1|??',
    '1|궁  예|똥마려',
    '2|관료 1|???',
    '1|궁  예|응가마려',
    '2|관료 1|????',
    '1|궁  예|나는 거시기 없어',
    '2|관료 1|?????',
    '1|궁  예|엄마도 없어',
    '2|관료 1|??????',
    '1|궁  예|매운거 먹으면 헙헙ㅎ헙ㅎ벟ㅂ헙',
    '2|관료 1|???????',
]

for txt in textes:
    tt = txt.split('|')
    set_color(16*int(tt[0]) + 15)
    print(" %s " % tt[1], end="")
    sys.stdout.flush()
    set_color(7)
    print(" %s" % tt[2])

이렇게 할 경우 아래와 같이 출력됩니다.

이를 활용하면 머드게임처럼 CLI 기반으로 돌아가는 게임을 만들 때도 유용합니다.

아, 참고로 이 병맛나는 텍스트의 출처는 https://youtu.be/gjQ7sEKoj7Y (궁예의 아무말 대잔치)

댓글 남기기

이메일은 공개되지 않습니다. 필수 입력창은 * 로 표시되어 있습니다