Qt程序的字符编码方式

摘要:
并且故意对源文件使用不适当的字符编码方法,导致其文本显示控件的中文字符被乱码。此qtmess.cpp使用Windows中的记事本以简体中文编辑。打开源文件编码选择对话框。Windows系统中的通用记事本、编辑器、VC++开发环境等都默认使用GBK汉字编码。Linux和Qt默认使用UTF-8国际文本编码。从编辑器中选择正确的编码以正常显示本地语言文本。检查源文件的编码格式并选择源文件编码。

本节会创建一个图形界面 Qt 程序,并故意对源文件使用不恰当的字符编码方式,导致其文本显示控件的汉字乱码。我们会介绍两种纠正方法:

  • 第一种是不修改源代码文件编码格式,通过 QString::fromLocal8Bit() 函数在程序运行时转码;
  • 第二种是直接将源代码文件整体转换成 UTF-8 编码,就不需要修改具体的代码行了。


第二种是最为推荐的方式,一劳永逸地解决乱码问题,UTF-8 是 Qt5 默认的编码方式。

乱码的示例程序

首先「猛击这里」下载 qtmess 示例程序,得到的是一个压缩包,解压到比如 D:QtDemoqtmess 文件夹里,然后用 QtCreator 打开该项目文件 qtmess.pro,看到项目配置提示界面:

Qt程序的字符编码方式第1张

 
一般选中 Select all kits ,然后点击 Configure Project ,让集成开发环境 QtCreator 自动配置好。

为了让例子尽可能简单,项目里面只有一个源文件 qtmess.cpp ,在项目视图打开该源代码文件,右边编辑器出现以下提示:

Qt程序的字符编码方式第2张

 编辑器默认是认识 UTF-8 编码的源文件,这个 qtmess.cpp 是在简体中文 Windows 里用记事本编辑的,其汉字编码格式是 GBK,所以上图中文出现乱码。右上角也提示出现解码错误,不能用默认的 UTF-8 格式解码。点击“Select Encoding”按钮,打开源文件编码选择对话框:

Qt程序的字符编码方式第3张

 对于简体中文,选择 GBK 打头的条目或 GB18030 打头的都可以,windows-936 和其他 CP936(CodePage)、MS936(Microsoft)是一个意思,大字符集 GB18030 也有其他称呼,如 ibm-1392,windows 代码页编号 54936。这里选择 GBK 的条目(GBK 条目有重复的,任选一个),然后点击“按编码重新载入”按钮,文件里的汉字就正常了:

Qt程序的字符编码方式第4张

 注意 UTF-8 和 GBK 其实对英文和数字都是一样的 ASCII 单字节编码,所以源文件用英文和数字是肯定不乱码,主要是汉字之类的本地语言文字编码显示容易出错。

Windows 系统里一般的记事本、编辑器、VC++ 开发环境等都是默认用 GBK 汉字编码,而 Linux 和 Qt 都是默认用 UTF-8 国际文字编码,所以文本显示乱码一般都是这个原因,从编辑器里选择正确的编码就可以正常显示本地语言文字了。

查看源文件的编码格式

选择源文件编码之后,GBK 编码文件和 UTF-8 编码文件都能正确显示,但怎么从 QtCreator 看到当前文件编码格式呢?这个是可以配置的,让 QtCreator 自动显示。点击菜单“工具”--> “选项”,在选项对话框左边选择“文本编辑器”,右边选择“显示”,看到下图:

Qt程序的字符编码方式第5张

 
选中“Display file encoding”,然后点击“OK”按钮,就可以在编辑器右上角看到当前文件的编码格式:

Qt程序的字符编码方式第6张

 现在右上角可以看到源文件编码“GBK”了,这其实是一个快捷按钮,打开可以弹出刚才的文件编码对话框的。

关于代码的说明

关于编辑器的编码显示介绍到这,下面解释一下源文件里的内容:

//qtmess.cpp
#include <QApplication>
#include <QTextBrowser>
#include <QDebug>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QString strText = QObject::tr("1234打印汉字");
    QTextBrowser tb;
    tb.setText(strText);
    tb.setGeometry(40, 40, 400, 300);
    tb.show();
   
    return a.exec();
}

代码中包含了 QApplication、QTextBrowser、QDebug 三个头文件,QTextBrowser 是一个只读的文本显示框,一般用于大段文字的显示,并可以选择(Ctrl+A)并复制(Ctrl+C)里面的文本;而之前用的 QLabel 一般用于短文本显示,没有复制文本的功能,QLabel 经常配合其他控件使用,显示相关信息。

在 main() 函数内部:

  • 第一句定义了 Qt 应用程序入口;
  • 第二句定义了一个 strText 字符串对象,里面有数字和汉字;
  • 第三句定义了 QTextBrowser 对象 tb,就是本程序的图形窗口;
  • 第四句设置文本框的文本内容为 strText ;
  • 第五句设置文本框的位置(屏幕左上角坐标 40,40)和尺寸(400*300);
  • 第六句是显示本程序的窗口;
  • 最后一句是进入应用程序的事件循环,直到退出。


代码比较简单,接下来我们点击 QtCreator 左下角的绿色三角形运行按钮,编译运行程序,看看效果:

Qt程序的字符编码方式第7张

 不出意外地,数字显示是正常的,汉字是乱码的,因为 Qt5 默认都是将源文件里的字符串当作 UTF-8 编码处理,GBK 多字节编码的汉字就会乱码。对于纠正乱码,正确的做法是将源文件的编码格式修改成 UTF-8,不推荐的做法是使用 QString::​fromLocal8Bit() 函数实现转码。我们先来看看不推荐的做法。

【不推荐】QString::​fromLocal8Bit() 函数实现转码

我们先采用不改变源文件编码的做法,而是通过修改具体的代码行,使用 QString::​fromLocal8Bit() 函数代替 tr() 函数来实现转码。修改 qtmess.cpp 源文件内容如下:

//qtmess.cpp
#include <QApplication>
#include <QTextBrowser>
#include <QDebug>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QString strText = QString::fromLocal8Bit("1234打印汉字");
    QTextBrowser tb;
    tb.setText(strText);
    tb.setGeometry(40, 40, 400, 300);
    tb.show();
   
    return a.exec();
}

面将原来的 QObject::tr() 函数替换成了 QString::fromLocal8Bit() 函数,因为只有一个字符串所以替换了一次,如果字符串特别多,那就非常麻烦了。而且变成 QString::fromLocal8Bit() 函数之后,就不能通过检测 tr() 函数进行国际化翻译了,所以这种做法是不推荐的。

点击 QtCreator 左下角运行按钮,看看运行效果:

Qt程序的字符编码方式第8张

 现在汉字是正常显示的,但代价是修改了代码行,如果字符串很多,那就麻烦了。

【推荐】将源文件改成 UTF-8 编码

将 qtmess.cpp 文件内容改回成原来的,还是使用原先的 QObject::tr() 封装字符串。在 QtCreator 编辑器右上角,点击文件编码的“GBK”字样:

 Qt程序的字符编码方式第9张

 在编码列表里找到“UTF-8”,选中该条目,然后点击右下角的“按编码保存”,QtCreator 会自动将文件内容转换成 UTF-8 格式存储,这样就不需要修改具体的代码行了:

Qt程序的字符编码方式第10张

 现在点击左下角运行按钮,同样可以看到正常的汉字显示。

本教程以后的全部文件格式都是按照 UTF-8 的编码,这也是 Qt5 默认的源文件编码格式,字符串也应该用 tr 函数封装,方便做国际化翻译。如果项目有面向国际化的要求,程序源代码里应该全部用英文和数字等 ASCII 码字符,尽量少用汉字,应当将汉字作为一个语言的翻译文件程序。本教程大多数例子都是不符合国际化标准的,因为方便大家看,作者自己也省事。读者实际的国际化项目开发中应该按照全英文的来写代码,然后将英文界面翻译成多种语言文字的。

转载:http://c.biancheng.net/view/5501.html

免责声明:文章转载自《Qt程序的字符编码方式》仅用于学习参考。如对内容有疑问,请及时联系本站处理。

上篇Xshell不能连接SSH的解决(附Kali2.0 SSH连接)用Python将word文件转换成html(转)下篇

宿迁高防,2C2G15M,22元/月;香港BGP,2C5G5M,25元/月 雨云优惠码:MjYwNzM=

相关文章

C++类相互包含

1. 两个类需要相互包含的情景 在观察者模式中,气象站的数据送给某些布告牌。 气象站要知道通知哪些布告牌,所以气象站类至少有一个布告牌类型的链表。 布告牌需要把自己注册到气象站类,告诉气象站类自己已经订阅消息, 注册函数需要气象站类作为形参,才知道自己注册到哪一个气象站。 也就是说,在类定义的时候,他们就是需要对方的! 所以,我需要在各自类定义的头文件中,...

关于 SetProcessWorkingSetSize 和内存释放

在应用程序中,往往为了释放内存等,使用一些函数,其实,对于内存操作函数要谨慎使用,比如大家常常想到的 SetProcessWorkingSetSize,其实对于windows来说,系统会自动在程序闲置时(如程序被最小化)释放内存的,自己用内存释放 时,往往会造成一些莫名的内存错误,造成自己的应用程序及系统不稳定。 具体原理有人已经写得很清楚了,以下为转帖的...

在linux7环境下安装oracle的问题记录

问题1 xhost:unable to open display oracle用户运行./runInstaller有如下提示: [oracle@yhxtest-1 database]$ ./runInstaller Starting Oracle Universal Installer... Checking Temp space: must be g...

服务器推送的实现—基于EventSource

一、服务器推送理解   首先要知道为什么使用服务器推送,回答这个问题其实就是相当于回答,服务器推送的优点,可以从两个方面来思考: 1.1 服务器推送的目的   及时的将客户端感兴趣的数据推送给它。 1.2 不是用服务器推送怎么来实现需求   不使用服务端推送,那就只能由客户端定期对服务器发送请求,来获取是否有需要的数据。这样做有几个缺点: 不能及时的获取...

【封装那些事】 未利用封装

未利用封装 客户代码使用显式类型检查(使用一系列if-else或switch语句检查对象的类型),而不利用出层次结构内已封装的类型变化时,将导致这种坏味。 为什么要利用封装? 一种臭名昭著的坏味是,在客户代码中使用条件语句(if-else或switch语句)来显式地检查类型,并根据类型执行相应的操作。我们这里讨论的是:要检查的类型都封装在了层次结构中,但...

JQuery表格操作的常用技巧总结

JQuery对表格进行操作的常用技巧。 1、表格奇数行和偶数行分别添加样式  复制代码代码如下: $(function(){  $('tr:odd').addClass("odd");  $('tr:even').addClass("even");  });  不算表的头部  复制代码代码如下: $(function(){  $('tbody>...