2011年2月10日 星期四

Console 顏色設定

想要將查詢過的單字,利用顏色來區分,例如查詢過一兩次的單字用橘色、查詢過很多次的就用紅色來提醒自己。

由於我在 windows 平台開發,因次要用到 win32 的 api 來處理顏色,這很惱人~
之前寫的 PTT 截圖程式,就是用 win32 api,主要是用 SetConsoleTextAttribute 這個 api 來設定顏色。程式碼如下:

Console::ColorType Console::set_color(ColorType color) throw(std::logic_error)
{
    CONSOLE_SCREEN_BUFFER_INFO csbi;
    WORD oldColor;

    if (GetConsoleScreenBufferInfo(out_, &csbi))
        oldColor = csbi.wAttributes;
    else
        throw std::logic_error("Can't Get Console Screen Buffer Info");

    if (color==0x00) color = FOREGROUND_RED | FOREGROUND_GREEN |
        FOREGROUND_BLUE | FOREGROUND_INTENSITY;

    /* set text and background color */
    SetConsoleTextAttribute(out_, color);
    /*
    FOREGROUND_BLUE(0x01), FOREGROUND_GREEN(0x02), FOREGROUND_RED(0x04), FOREGROUND_INTENSITY(0x08),
    BACKGROUND_BLUE(0x10), BACKGROUND_GREEN(0x20), BACKGROUND_RED(0x40), BACKGROUND_INTENSITY(0x80)
    ex: FOREGROUND_RED | FOREGROUND_GREEN | FOREGROUND_BLUE
    */
    return oldColor;
}

在 codeproject 找到了一篇文章,利用 IO manipulator 來包裝使得改變顏色變得很輕鬆。

Add Color to Console Projects
注意此文章的 Points of Interest 有說明 IO Manipulator 的運作原理。


程式碼如下:
//------------------------------------------------------------------------------
// Console.h: interface for the Console manipulators.
//------------------------------------------------------------------------------

#if !defined( CONSOLE_MANIP_H__INCLUDED )
#define CONSOLE_MANIP_H__INCLUDED

//------------------------------------------------------------------------------

//------------------------------------------------------------------"includes"--
#include <iostream>
#include <iomanip>
#include <windows.h>

namespace JadedHoboConsole
{
static const WORD bgMask( BACKGROUND_BLUE |
BACKGROUND_GREEN |
BACKGROUND_RED |
BACKGROUND_INTENSITY );
static const WORD fgMask( FOREGROUND_BLUE |
FOREGROUND_GREEN |
FOREGROUND_RED |
FOREGROUND_INTENSITY );

static const WORD fgBlack ( 0 );
static const WORD fgLoRed ( FOREGROUND_RED );
static const WORD fgLoGreen ( FOREGROUND_GREEN );
static const WORD fgLoBlue ( FOREGROUND_BLUE );
static const WORD fgLoCyan ( fgLoGreen | fgLoBlue );
static const WORD fgLoMagenta( fgLoRed | fgLoBlue );
static const WORD fgLoYellow ( fgLoRed | fgLoGreen );
static const WORD fgLoWhite ( fgLoRed | fgLoGreen | fgLoBlue );
static const WORD fgGray ( fgBlack | FOREGROUND_INTENSITY );
static const WORD fgHiWhite ( fgLoWhite | FOREGROUND_INTENSITY );
static const WORD fgHiBlue ( fgLoBlue | FOREGROUND_INTENSITY );
static const WORD fgHiGreen ( fgLoGreen | FOREGROUND_INTENSITY );
static const WORD fgHiRed ( fgLoRed | FOREGROUND_INTENSITY );
static const WORD fgHiCyan ( fgLoCyan | FOREGROUND_INTENSITY );
static const WORD fgHiMagenta( fgLoMagenta | FOREGROUND_INTENSITY );
static const WORD fgHiYellow ( fgLoYellow | FOREGROUND_INTENSITY );
static const WORD bgBlack ( 0 );
static const WORD bgLoRed ( BACKGROUND_RED );
static const WORD bgLoGreen ( BACKGROUND_GREEN );
static const WORD bgLoBlue ( BACKGROUND_BLUE );
static const WORD bgLoCyan ( bgLoGreen | bgLoBlue );
static const WORD bgLoMagenta( bgLoRed | bgLoBlue );
static const WORD bgLoYellow ( bgLoRed | bgLoGreen );
static const WORD bgLoWhite ( bgLoRed | bgLoGreen | bgLoBlue );
static const WORD bgGray ( bgBlack | BACKGROUND_INTENSITY );
static const WORD bgHiWhite ( bgLoWhite | BACKGROUND_INTENSITY );
static const WORD bgHiBlue ( bgLoBlue | BACKGROUND_INTENSITY );
static const WORD bgHiGreen ( bgLoGreen | BACKGROUND_INTENSITY );
static const WORD bgHiRed ( bgLoRed | BACKGROUND_INTENSITY );
static const WORD bgHiCyan ( bgLoCyan | BACKGROUND_INTENSITY );
static const WORD bgHiMagenta( bgLoMagenta | BACKGROUND_INTENSITY );
static const WORD bgHiYellow ( bgLoYellow | BACKGROUND_INTENSITY );

static class con_dev
{
        private:
HANDLE hCon;
DWORD cCharsWritten;
CONSOLE_SCREEN_BUFFER_INFO csbi;
DWORD dwConSize;

        public:
con_dev()
{
hCon = GetStdHandle( STD_OUTPUT_HANDLE );
}
        private:
void GetInfo()
{
GetConsoleScreenBufferInfo( hCon, &csbi );
dwConSize = csbi.dwSize.X * csbi.dwSize.Y;
}
        public:
void Clear()
{
COORD coordScreen = { 0, 0 };

GetInfo();
FillConsoleOutputCharacter( hCon, TEXT(' '),
dwConSize,
coordScreen,
&cCharsWritten );
GetInfo();
FillConsoleOutputAttribute( hCon,
csbi.wAttributes,
dwConSize,
coordScreen,
&cCharsWritten );
SetConsoleCursorPosition( hCon, coordScreen );
}
void SetColor( WORD wRGBI, WORD Mask )
{
GetInfo();
csbi.wAttributes &= Mask;
csbi.wAttributes |= wRGBI;
SetConsoleTextAttribute( hCon, csbi.wAttributes );
}
} console;

inline std::ostream& clr( std::ostream& os )
{
os.flush();
console.Clear();
return os;
};

inline std::ostream& fg_red( std::ostream& os )
{
os.flush();
console.SetColor( fgHiRed, bgMask );

return os;
}

inline std::ostream& fg_green( std::ostream& os )
{
os.flush();
console.SetColor( fgHiGreen, bgMask );

return os;
}

inline std::ostream& fg_blue( std::ostream& os )
{
os.flush();
console.SetColor( fgHiBlue, bgMask );

return os;
}

inline std::ostream& fg_white( std::ostream& os )
{
os.flush();
console.SetColor( fgHiWhite, bgMask );

return os;
}

inline std::ostream& fg_cyan( std::ostream& os )
{
os.flush();
console.SetColor( fgHiCyan, bgMask );

return os;
}

inline std::ostream& fg_magenta( std::ostream& os )
{
os.flush();
console.SetColor( fgHiMagenta, bgMask );

return os;
}

inline std::ostream& fg_yellow( std::ostream& os )
{
os.flush();
console.SetColor( fgHiYellow, bgMask );

return os;
}

inline std::ostream& fg_black( std::ostream& os )
{
os.flush();
console.SetColor( fgBlack, bgMask );

return os;
}

inline std::ostream& fg_gray( std::ostream& os )
{
os.flush();
console.SetColor( fgGray, bgMask );

return os;
}

inline std::ostream& bg_red( std::ostream& os )
{
os.flush();
console.SetColor( bgHiRed, fgMask );

return os;
}

inline std::ostream& bg_green( std::ostream& os )
{
os.flush();
console.SetColor( bgHiGreen, fgMask );

return os;
}

inline std::ostream& bg_blue( std::ostream& os )
{
os.flush();
console.SetColor( bgHiBlue, fgMask );

return os;
}

inline std::ostream& bg_white( std::ostream& os )
{
os.flush();
console.SetColor( bgHiWhite, fgMask );

return os;
}

inline std::ostream& bg_cyan( std::ostream& os )
{
os.flush();
console.SetColor( bgHiCyan, fgMask );

return os;
}

inline std::ostream& bg_magenta( std::ostream& os )
{
os.flush();
console.SetColor( bgHiMagenta, fgMask );

return os;
}

inline std::ostream& bg_yellow( std::ostream& os )
{
os.flush();
console.SetColor( bgHiYellow, fgMask );

return os;
}

inline std::ostream& bg_black( std::ostream& os )
{
os.flush();
console.SetColor( bgBlack, fgMask );

return os;
}

inline std::ostream& bg_gray( std::ostream& os )
{
os.flush();
console.SetColor( bgGray, fgMask );

return os;
}
}

//------------------------------------------------------------------------------
#endif //!defined ( CONSOLE_MANIP_H__INCLUDED )


於是設定顏色就和使用 std::setw(10) 的方式一樣:

#include "Console.h"


namespace con = JadedHoboConsole;

int main()
{
using std::cout;
using std::endl;

cout << "I like " << con::fg_green << "green" << con::fg_white << " eggs and ham." 
<< endl;
}

舒服!!

1 則留言:

  1. 這片文章花了很長的時間在處理如何貼程式碼 = =

    這篇有教學,只是對於水平軸的顯示我還不知道要到哪裡設定,可能這個樣本對於水平軸本來就不支援。
    http://klcintw4.blogspot.com/2006/11/blog-post_03.html


    另外一篇,這個方法就可以出現水平軸,只是會有 < > 顯示的問題 = =
    http://blog.uioiu.com/2009/11/blogger-syntax-highlighting.html

    還有加上 hover 滑鼠移動時,可以調整 code 框的 size

    回覆刪除