龙空技术网

轻松玩转windows控制台(一):窗口标题

段誉和语言 379

前言:

此时看官们对“对话框和窗口的作用是一样的吗”都比较关注,姐妹们都需要了解一些“对话框和窗口的作用是一样的吗”的相关内容。那么小编在网摘上收集了一些有关“对话框和窗口的作用是一样的吗””的相关资讯,希望朋友们能喜欢,兄弟们快快来学习一下吧!

开篇预告

前段时间,我在其他平台发布了一篇介绍“轻松玩转windows控制台”的文章,被不少粉丝私信批评,甚至还有个别言辞激烈的。

是因为文章写的不好吗?应该不是,因为两天时间就突破了90多个收藏,说明大家还是挺喜欢这种实用的、技巧性的技术文章,但是为什么还是被批评呢?

因为文章通篇以代码为主,虽然功能很多,但并没有详细的解释,导致大家在用的时候,有很多地方出现问题。

基于此,我决定围绕“轻松玩转windwos控制台”主题,写一个系列性的文章,通过详细介绍控制台方面的各种操作技巧,从而提高c语言初学者的学习兴趣。

我大致的规划主要分为这几块:

第一个系列是对控制台的各种“魔改”,包括标题修改、输出文字的字体大小、字体样式、文字颜色、屏幕背景颜色、控制台窗口的移动、居中显示、窗口大小、以及文字在窗口内任意位置的显示、中文字符的正确显示等等。

这个系列看完之后,就开始发布控制台窗口的图形化操作的系列文章。

比如控制台如何控制鼠标、键盘,如何将屏幕背景改成彩色图片,如何在控制台内实现动画效果等等。为后面第三个系列控制台图形游戏开发打下基础。

第三个系列我准备围绕一个游戏的一步步实现来发布文章,可以是一个超级玛丽游戏,或者一个台球游戏都可以,游戏本身我早就已经调测运行。

话不多说,开始我们的第一个“玩转之旅”。

控制台介绍

本段是控制台的基础介绍,大家不感兴趣,可以直接跳过,也不影响后面阅读。

我们用c语言刚刚编写程序时,一般都是会在屏幕上弹出一个黑乎乎的窗口,然后黑底白字的显示一行行内容。这个黑乎乎的窗口界面,我们一般称为“控制台”,英文是Console,而在控制台界面内运行的程序,我们一般称为“控制台程序”。

我们把通过控制台运行程序的方式,称为CUI,即Command User Interface,命令用户界面。相对应的,还有一种图形化用户界面,GUI,即Graphics User Interface。有时候,我们也把CUI模式称为CLI模式,即Command Line Interface ,命令行界面,都可以。

我们一般通过执行cmd.exe命令进入控制台窗口,从而运行控制台程序。

以上这些都是最基础的概念,后面文章中用到什么就介绍什么,尽量降低复杂度。

控制台标题(Console Ttile)

我们先从控制台标题入手。

控制台程序启动时,窗口上方会有一个title(标题)。这个title显示的是程的绝对路径和程序名称。这个title字符串我们称为“原始的窗口标题名称”,即original title。如图:

这个字符串显示的真的很丑,我们一般都会改成我们喜欢的内容,如下所示:

围绕控制台窗口的标题,可以实现三个功能。分别是“修改控制台标题”、“获取控制台标题”、“获取原始控制台标题”。控制台标题被我们修改以后,有时候我们可能需要知道程序所在的绝对路径和程序名称,通过“获取原始控制台标题”这个功能就很方便。下面来看一下这3个功能对应的函数如何使用的, 并简单的介绍下windows的win32API调用。

注释:如果对Win32API不感兴趣,可以直接复制代码使用即可。

功能:修改控制台标题

若修改控制台当前标题,需要用到的函数原型如下:

BOOL  SetConsoleTitle(LPCTSTR  lpConsoleTitle);

在学习如何使用这个函数时,我们先介绍一下一些windos程序设计的基本概念,以便于后面能熟练的使用各种控制台函数。

对初学者而言,使用windows的API函数,应该会有段很痛苦的适应过程。因为微软把c/c++的基本数据类型和自定义数据类型,都采用了匈牙利命名法进行了封装,我本人对这个命名法是非常厌恶的,但是还是要学习下。[狗头]

函数名: SetConsoleTitle,设置当前控制台标题。参数类型:LPCTSTR,这是微软开发团队自定义的数据类型,我们来分析下。

L表示long类型,用来表示长整型数据;P是pointer,表示指针类型;LP表示长整型指针(即32位或64位指针类型,取决于系统是32位或64位);C表示const,LPC表示这个指针类型指向的数据是常量数据;T是type,用来表示通用类型的含义(泛型),表示有unicode版本,或者ANSI版本,暂时不用理会;STR是字符串string的含义。

下面我列个表,就看的比较清爽了。

L:long类型P:pointer,指针类型LP:长整型指针C:constLPC:指针指向常量T:type,泛型(暂时忽略)STR:string,字符串LPCTSTR:LP + C + (T) + STR

由此可知,LPCTSTR,就是一个指向字符串常量的指针(字符串本身就是常量数据),可以近似理解成c语言中的const char*。

返回值:BOOL

BOOL,就是布尔类型,其实就是一个int类型:

typedef  int BOOL;

如果真,就是TRUE,假就是FALSE。其实TRUE就是1,FALSE就是0。

本函数的参数是输入型参数(什么是输入型参数和输出型参数,可以查看我的这篇文章:c语言解剖课:函数的输入参数和输出参数)

这个参数在使用之前,其所在的外部变量是一个字符指针类型,必须被初始化,并且已经存放了新的标题字符串,字符个数必须小于 64K(等于64*1024个字节,谁能用这么多?)当函数执行成功,当前标题修改成新的字符串时,就返回为TRUE,执行失败就返回FALSE。

我们来写一个演示代码:

#include <stdio.h>#include <windows.h>int main() {    LPCSTR newStr = "hello,title!" ;    if(SetConsoleTitle(newStr) == TRUE){        printf("Title is changed!\n");    }    system("pause");    return 0;}

首先,文件的后缀需要是.cpp或其他C++源文件的格式,而不能是.c的后缀了。

其次,需要包含windows.h头文件,因为对控制台操作的函数,都是这个头文件提供的。我们需要先定义一个字符串,存放新的标题。

当然,你也可以用 char* 来定义,但是建议最好和windows编程风格保持一致,就用这个非常别扭的 LPCSTR类型,然后判断是否设置成功。

随后的System函数,参数是一个字符串,这个字符串实际上就是一个DOS命令,这里是一个暂停命令。如果没有这条语句,运行这个程序时,屏幕会一闪而过。运行效果如图:

窗口中的“请按任意键继续...”,就是system("pause");这行代码中的pause暂停命令起的作用。当然,为了简洁,你也可以直接写成如下形式:

#include <stdio.h>#include <windows.h>int main() {    SetConsoleTitle("hello,title!");    system("pause");    return 0;}

但是,最好不要这么写,因为随着功能越来越强大(复杂),会很不利于维护。那么我们想显示中文行不行?我们先测试一下,请看下面这段代码:

#include <windows.h>int main() {    SetConsoleTitle("你好世界");    system("pause");    return 0;}

看一下执行的效果,如图:

控制台标题输出的是乱码,当然,有可能你的编译器运行后,输出的是中文。没关系,继续往下看就好了。为什么会这样?不用急。我们右击标题栏,点“属性”进去,注意看,下面这个截图中的红框,显示了系统当前使用的编码。

代码页,即Code Page,简写为CP,表明了当前控制台的编码情况。如果是437,则是美国英语;如果是936,则是ANSI/OEM - 简体中文默认的GBK编码;如果是950 ,则是繁体中文;如果是65001,则是UTF-8编码。当然,代码页有很多种,我们只需要关心一个就可以了,就是UTF-8编码。用列表显示代码页标识符和编码标准,会更清楚:

437 :美国英语936 : ANSI/OEM - GBK950 : 繁体中文650001 :UTF-8

如果控制台显示乱码,我们可以将当前代码页设置为65001,即UTF-8,就可以正确显示中文。注意,并不是因为当前代码页是936,所以就显示乱码。

显示乱码是编译器的编码规范和系统的编码规范不一致,需要手动修改编码规范。通过下面介绍的方法,通过修改代码页为UTF-8,可以快速解决问题,但不是唯一的解决办法。

函数SetConsoleCP是设置控制台输入字符使用的编码标准,SetConsoleOutputCP是设置控制台输出字符的编码标准,函数原型如下:

BOOL  SetConsoleCP(UINT  wCodePageID);BOOL  SetConsoleOutputCP(UINT  wCodePageID);

参数类型:UINT

微软将基本数据类型int封装成INT,约定为32位的有符号整数,取值范围是 -2147483648 到 2147483647。即:

typedef int INT;

而无符号整型unsigned int 被封装成UINT,约定为32位无符号整数,取值范围为 0 到 4294967295。即:

typedef  unsigned  int  UINT;

参数的值就是代码页的标识符,比如要显示中文,UINT变量的值就是655001即可。

返回值是BOOL类型,前已介绍过,如果执行成功,则返回TRUE,否则返回FALSE。

举例如下:

#include <stdio.h>#include <windows.h>int main() {    SetConsoleCP(65001);//控制台标题    SetConsoleOutputCP(65001);//输出内容    LPCSTR newStr = "你好世界!" ;    if(SetConsoleTitle(newStr) == TRUE){        printf("标题修改成功!\n");    }    system("pause");    return 0;}

我们看下执行结果:

我们通过SetConsoleOutputCP,设置了输出字符的代码页(Code Page,CP)为UTF-8,所以prinftf函数的输出内容,正常显示中文了,同样的输入字符显示中文,通过SetConsoleCP就可以了。

进一步的,我们在程序里,如果需要显示中文,我们需要知道当前代码页的数值是不是65001,如果不是,我们需要设置成6501。我们如知晓呢?

可以通过GetConsoleCP获取输入状态的代码页,GetConsoleOutputCP获取输出状态的代码页,从而进行判断。函数原型如下:

UINT GetConsoleCP(void);UINT WINAPI GetConsoleOutputCP(void);

这两个函数没有参数,返回值是UINT类型,也就是当前所用的代码页标识符。第一个函数返回的是输入模式的代码页标识符,第二个函数返回的是输出模式的代码页标识符。通过对代码页判断,然后始终保持当前代码页标识符为65001即可。

示例代码如下:

#include <stdio.h>#include <windows.h>int main(){    UINT codePage = GetConsoleOutputCP();    if(codePage != 65001){        SetConsoleCP(65001);        SetConsoleOutputCP(65001);    }    LPCSTR newStr = "你好,世界!" ;    if(SetConsoleTitle(newStr) == TRUE){        printf("标题修改成功!\n");    }    return 0;}

我们现在可以随心所欲的修改窗口标题名了,并且也可以正确显示中文内容了。接下来,我们如何获取当前窗口的标题名呢?

功能:获取控制台标题

通过GetConsoleTtile函数,就可以获取道当前控制台的标题。函数原型如下:

DWORD  GetConsoleTitle(LPTSTR  lpConsoleTitle, DWORD  nSize );

函数名: GetConsoleTitle;第一个参数类型:LPTSTR

这个参数的类型和上面介绍的SetConsoleTtitle函数的LPCTSTR类型,很相似。本质的区别在于字母C,LPCTSTR是指向常量字符串,不允许修改,属于输入性参数。而LPTSTR类型,指向的是可以被修改的一段区域,一般我们定义成一个数组,或者一段动态内存分配区域。

第二个参数类型:DWORD

windows编程规范中,把8个位(bit)当作1个字节BYTE,把2个BYTE当作1个字,即WORD,2个WORD为双字,即DOUBLE WORD,简写为DWORD。

1个DWORD类型的变量,等于4个字节,表示32 位无符号整数。 范围为 0 到十进制4294967295。其实就是c语言中的 unsigned long ,实际上也是这样定义的:

typedef  unsigned long  DWORD;

返回值和第二个参数一样,也是DWORD。

第一个参数是输出型参数,接受函数的返回数据。(什么是输入型参数和输出型参数,可以查看我的这篇文章:c语言解剖课:函数的输入参数和输出参数),用来存放获取的当前窗口标题字符串。

第二个参数是要显式的说明第一个参数所指向的内存区域的大小,以字符为单位。

如果函数成功,则返回值为控制台窗口标题的字符个数。如果函数失败,则返回值为零。

下面是一段演示代码:

#include <stdio.h>#include <windows.h>#include <stdlib.h>#include <malloc.h>int main(){    DWORD charactor_total = MAX_PATH;    LPTSTR title = (LPTSTR)malloc(sizeof(CHAR)*MAX_PATH);    DWORD n = GetConsoleTitle(title,charactor_total);    printf("标题字符个数:%d\n",n);    system("pause");    return 0;}

程序执行结果如图:

大家可以数一下标题的字符数,是不是91个。[憨笑]

功能:获取原始标题

当控制台窗口标题被修改后,我们有时候需要获取窗口的原始标题,也就是程序的绝对路径和程序全名(包括后缀),这非常有用,因为可以根据这个字符串提取出程序文件所在的目录。

获取原始标题的函数为GetConsoleOriginalTitle(),当窗口标题未被修改时,GetConsoleTtile()和它的功能是一样的,当被修改后,就出现了本质的差别,所以小心不要用错函数。

函数原型如下:

DWORD GetConsoleOriginalTitle( LPTSTR lpConsoleTitle, DWORD nSize);

这个函数的参数和用法,就不再讲解,和GetConsoleTitle函数类似。

总 结

今天因为是第一篇文章,特别是对windows程序设计比较陌生的读者,对微软的自定义数据结构估计也会不适应,所以本文对微软自定义的数据结构讲解的比较详细,后面文章都会对出现的数据结构进行详细讲解,感兴趣的读者可以持续关注我,感谢。

段誉,2024年2月9日(除夕),写于合肥。

标签: #对话框和窗口的作用是一样的吗 #对话框和窗口的作用是一样的吗为什么 #c语言调用函数返回值是bool怎么写 #控制台一闪