當前位置: 華文世界 > 科技

輕松玩轉windows控制台(二):彩色文字和彩色背景

2024-02-11科技

寫在前面

在上一篇文章中,詳細的介紹了如何修改控制台視窗的標題,如何獲取當前視窗標題,如何獲取視窗的原始標題,並透過原始標題獲取程式的絕對路徑等程式碼範例。輕松玩轉windows控制台(一):視窗標題

本篇文章將更加有趣,介紹如何將控制台螢幕上的文字設定各種顏色,以及文字的背景顏色也可以設定成各種色彩。

本篇只負責演示如何設定彩色文字和彩色螢幕,不負責審美。。。[憨笑]也就是說,我的文字和螢幕的配色可能會醜的逮鬼,但是沒辦法,我的審美只能是這樣。

話不多說,進入正題。

一般的,我們將螢幕上文字的顏色,稱為 前景色 。將文字所在的螢幕區域的顏色,稱為 背景色 。在下面的文章中,有時可能會將 文字顏色 和前景色混用,將 螢幕顏色 和背景色混用。他們是等價的。

方法1:color命令

windows系統的DOS命令還是挺強大的,特別是現在PowerShell(類似於經典控制台)更是有點趕上Linux的Shell的感覺(臆想而已)。

color命令,就是其中的一個DOS命令。詳細用法此處不展開,如果想了解所有用法,可以在控制台輸入:color /? 即可,螢幕截圖如下:

現在如果我們希望螢幕顏色是亮白色,文字顏色是紅色,那麽程式碼如下:

#include <stdio.h>#include <windows.h>int main() { system("color F4"); printf("c是程式設計師的母語。\n"); printf("你好,世界!\n"); system("pause"); return 0;}

執行後,控制台文字和螢幕顏色如下:

如果用color命令,那麽顏色只能從下面顏色列表裏選擇:

  • 0 :黑色
  • 1 :藍色
  • 2: 綠色
  • 3:淺綠色
  • 4:紅色
  • 5:紫色
  • 6:黃色
  • 7:白色
  • 8:灰色
  • 9:淡藍色
  • A:淡綠色
  • B:淡淺綠
  • C:淡紅色
  • D:淡紫色
  • E:淡黃色
  • F:亮白色
  • 數位序列由2個16進制數位組成,第一個數位表示螢幕顏色,第二個數位表示文字顏色。比如F4,第一個數位F,代表螢幕是亮白色,第二個數位4代表文字顏色紅色。

    color命令是全域性質的,也就是說會在程式執行期間一直生效的。除非下次用clor命令重新設定顏色,而且每次必須是2個數位成對出現。

    比如如下程式碼,可以靈活控制螢幕和文字的顏色顯示:

    #include <stdio.h>#include <windows.h>int main() { system("color F4"); printf("現在顯示白底還字。\n"); system("pause"); system("color 4F"); printf("現在顯示紅底白字。\n"); system("pause"); return 0;}

    下面兩張截圖,分別演示了兩次設定顏色時的效果:

    按任意鍵之前

    按任意鍵之後

    這個方法最大的問題,在於顏色只能從這16個(0到F)十六進制數裏選擇,色彩非常單一。能不能透過RGB值,來進行調色?這樣顯示效果就會非常豐富。

    方法2:wprintf函式

    我們可以透過打印一種特定的格式字元來控制螢幕和文字的顏色顯示。比如需要藍底黃字的顯示效果,那麽下面這段程式碼就可以實作:

    #include <stdio.h>#include <Windows.h>#include <wchar.h>//wprintf函式的表頭檔:wchar.hint main(){ HANDLE hd; hd = GetStdHandle(STD_OUTPUT_HANDLE); if(hd == INVALID_HANDLE_VALUE) return GetLastError(); DWORD dm = 0; if(!GetConsoleMode( hd, &dm)) return GetLastError(); dm |= 0x0004; if(!SetConsoleMode( hd, dm)) return GetLastError(); int r1,g1,b1,r2,g2,b2; //bg color,color:blue r1 = 0,g1 =0,b1 = 255; //fore color,clor:yellow r2 = 255,g2 = 255,b2 = 0; wprintf(L"\x1b[38;2;%d;%d;%dm\x1b[48;2;%d;%d;%dmHello,C language!\n",r2,g2,b2,r1,g1,b1); system("pause"); return 0;}

    顯示的效果如圖:

    我們來詳細的解釋下這段程式碼。

    表頭檔部份,和上一篇中的程式碼相比,多了一個wchar.h 的表頭檔,下面程式碼中顏色的顯示需要用到 wprintf函式,這個函式屬於wchar.h。

    在main函式的第一行程式碼中,GetStdHandle函式的參數STD_OUTPUT_HANDLE是一個預定義的常量,用於表示標準輸出裝置的控制代碼。

    所謂標準輸出裝置,就是指控制台視窗。控制代碼我們就理解為一個唯一的識別元,類似於指向某個物件的指標,比如控制台視窗的控制代碼,就類似於指向這個控制台視窗的指標。

    初學者學習windows編程,不能深究細節,前期多以模仿常式程式碼為主,這樣能逐漸建立起windows編程的感覺。很多人不是因為學習難度大,而放棄了windows編程,而是細節太多,學著學著就迷失了。

    除非必要,後面不展開細節,只是提一下相關知識點。

    我們現在學習的是如何使用、操作當前的控制台視窗,控制台視窗我們可以啟動很多個,而如何獲得我們當前正在用的這個控制台視窗物件呢?

    就是透過GetStdHandle函式獲得,參數就是STD_OUTPUT_HANDLE。

    總結一下:HANDLE hd = GetStdHandle(STD_OUTPUT_HANDLE); 就是獲得當前正在使用的控制台表單的控制代碼。

    if(hd == INVALID_HANDLE_VALUE) return GetLastError();

    INVALID_HANDLE_VALUE,見名知義,表示無效的控制代碼值,如果沒有正確獲取控制代碼值,就透過GetLastError函式輸出錯誤原因(每一個錯誤程式碼,對應著一個錯誤的原因,此處不展開)

    GetConsoleMode函式是獲取當前控制台的模式,所謂控制台模式,暫時不用細究。

    DWORD dm = 0;if(!GetConsoleMode( hd, &dm)) return GetLastError();dm |= 0x0004;if(!SetConsoleMode( hd, dm)) return GetLastError();

    這段程式碼就是設定控制台模式,細節暫時不展開分析,只要記住,這段程式碼必須要有,最好不要直接使用後面的wprintf函式,因為這段程式碼實際上就是對各種可能的異常現象進行了判斷並做了處理。

    wprintf(L"\x1b[38;2;%d;%d;%dm\x1b[48;2;%d;%d;%dmHello,C language!\n",r2,g2,b2,r1,g1,b1);

    這個函式,類似於常用的printf函式。我們現在來稍微詳細的講解下。

    函式第一個參數,是一個字串,類似於printf函式,但是字串前面一定要加上一個 大寫字母L 。雙引號中的 \x1b[38;2;%d;%d;%dm ,是一段完整的功能控制的格式字串。說人話,就是透過這段程式碼來實作文字顏色的改變。

    \x1b[...m中的...省略號裏可以實作各種控制功能,以後會詳細講解,現在只解釋文字顏色的改變。 38表示是設定前景色 。第一個%d代表的是RGB值中的R值,後面的2個%d分別是G值和B值。關於RGB值,此處不展開,大家自行了解。

    如果38改成48,則是背景色的RGB值。後面的hello,C language!\n ,正常輸出。這個字串必須是英文的。如果顯示中文,最簡單的辦法,就是用另外的printf函式輸出即可。關於中文輸出,上一篇已經介紹過,有很多辦法,最簡單的就是將當前控制台的內碼表設定為UTF-8。

    比如下面這樣,就比較靈活。

    #include <stdio.h>#include <Windows.h>#include <wchar.h>int main(){ HANDLE hd; hd = GetStdHandle(STD_OUTPUT_HANDLE); if(hd == INVALID_HANDLE_VALUE) return GetLastError(); DWORD dm = 0; if(!GetConsoleMode( hd, &dm)) return GetLastError(); dm |= 0x0004; if(!SetConsoleMode( hd, dm)) return GetLastError(); int r1,g1,b1,r2,g2,b2; //bg color,color:blue r1 = 0,g1 =0,b1 = 255; //fore color,clor:yellow r2 = 255,g2 = 255,b2 = 0; wprintf(L"\x1b[38;2;%d;%d;%dm\x1b[48;2;%d;%d;%dm",r2,g2,b2,r1,g1,b1); printf("現在是藍底黃字。\n"); wprintf(L"\x1b[38;2;%d;%d;%dm",255,0,0); printf("現在是藍底紅字。\n"); wprintf(L"\x1b[48;2;%d;%d;%dm",0,255,0); printf("現在是綠底紅字。\n"); wprintf(L"\x1b[48;2;%d;%d;%dm\x1b[38;2;%d;%d;%dm",255,0,255,0,255,255); printf("現在是顏色很醜。\n"); system("pause"); return 0;}

    程式執行的效果如下:

    這個方式和方法1的最大不同,一個是RGB值可以調增,另外就是 只影響當前和以後的文字和螢幕的顏色 ,而color命令則是會將之前的文字和螢幕的顏色,都修改成現在的設定。

    方法3:printf函式

    我們不使用wchar.h裏的wprintf函式,直接使用printf函式行不行?也可以。但是兩者用的格式字串有區別的。

    在wpritf函式中,格式字串裏的38代表前景色,48代表背景色。而直接使用printf函式的話,也是透過格式字串」\x1b[...m」來實作,但是細節有所不同。

    其中省略號位置是顏色值,多個顏色值之間用分號間隔。比如\x1b[%d;%dm,多個參數之間用分號分割。前景色的取值何顏色如下:

  • 30: 黑
  • 31: 紅
  • 32: 綠
  • 33: 黃
  • 34: 藍
  • 35: 紫
  • 36: 深綠
  • 37: 白
  • 背景色的取值何顏色對照如下:

  • 40:黑
  • 41:紅
  • 42:綠
  • 43:黃
  • 44:藍
  • 45:紫
  • 46:深綠
  • 47: 白
  • 我們透過一段程式碼,來看下:

    #include <stdio.h>#include <stdlib.h>#include <windows.h>int main(){ HANDLE hOut = GetStdHandle(STD_OUTPUT_HANDLE); if (hOut == INVALID_HANDLE_VALUE) return GetLastError(); DWORD dwMode = 0; if (!GetConsoleMode(hOut, &dwMode)) return GetLastError(); dwMode |= 0x0004; if (!SetConsoleMode(hOut, dwMode)) return GetLastError(); printf("\x1b[%d;%dm",34,43); printf("藍底黃字的彩色字型。\n"); system("pause");}

    程式執行效果如下:

    這段程式碼中,首先最開始的例外處理程式碼,不能省略,必須要有。\x1b[為控制格式符的開始,m 為控制格式符的結束,多個%d用;分割, 將根據數值來判斷是前景色還是背景色 。如果是41-47,就是背景色。如果是31-37,就是前景色。

    總 結

    其實格式控制字串功能非常強大,除了顯示顏色前景色和背景色,還可以對文字實作其他更強大的功能,比如給文字添加底線,甚至還可以移動當前光標的位置。

    下一篇文章我們詳細介紹透過各種格式控制符來實作一些控制台操作中的有趣功能。