当前位置: 华文世界 > 科技

轻松玩转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,就是前景色。

    总 结

    其实格式控制字符串功能非常强大,除了显示颜色前景色和背景色,还可以对文字实现其他更强大的功能,比如给文字添加下划线,甚至还可以移动当前光标的位置。

    下一篇文章我们详细介绍通过各种格式控制符来实现一些控制台操作中的有趣功能。