QT中出现的中文乱码问题及其解决方案

基本概念

字库表:是一个系统支持的文字,符号,数字的集合。
编码字符集(字符集):计算机是以二进制的形式存储字符的,每个字符对应的二进制编码不同,而编码字符集就是所有编码与字符的映射集合。例如:在ASCII码的编码字符集中,字母A的编码是65,65的二进制就是01000001。
字符编码:不同字符的编码不同,其二进制的位数也不同。为了达到节省空间,解析方便等目的,出现了多种存储字符编码的方式,每种方式对应一套算法,这套算法也称字符编码。例如Unicode字符集,utf-8,utf-16字符编码。
源文件字符集:源文件本身也是文本文件,所以源文件字符集是指源文件保存时采用哪种字符编码。
执行字符集:可执行应用程序内使用何种字符编码。编译器会将源码字符集转换为执行字符集。

情况一

软件平台:Windows 10,Qt Cretor 4.7.2,
问题描述:运行一个基于QT框架的的GUI应用程序时,界面上的PlainTextEdit组件无法正常显示中文形式的QString字符串,此外,在控制台中,也无法正常输出中文形式的QString字符串,即都出现了中文乱码。如下所示:

void Dialog::on_pushButton_clicked()
{//QHostInfo获取主机信息
  QString hostName=QHostInfo::localHostName(); //本地主机名
  ui->plainTextEdit->appendPlainText("本机主机名:"+hostName+"\n");
  QHostInfo hostInfo=QHostInfo::fromName(hostName); //本机IP地址

  QList<QHostAddress> addList=hostInfo.addresses(); // IP地址列表
  if(!addList.isEmpty())
    for(int i=0;i<addList.count();i++)
    {
      QHostAddress aHost=addList.at(i); //每一项是QHostAddress
      bool show=ui->checkBox->isChecked(); //只显示IPv4
      if(show)
        show=(QAbstractSocket::IPv4Protocol==aHost.protocol()); //IPv4协议
      else
        show=true;
      if(show)
      {
        ui->plainTextEdit->appendPlainText("协议:"+protocolName(aHost.protocol()));
        ui->plainTextEdit->appendPlainText("本机IP地址:"+aHost.toString());
        ui->plainTextEdit->appendPlainText("");
      }
    }

}

在这里插入图片描述

QString hello="中文";
  qDebug()<<hello;

在这里插入图片描述

QString显示中文乱码的原因

QString的内部采用unicode字符集,utf-16编码。构造函数QString::QString(const char *str)默认使用fromUtf8()将str所指的执行字符集从utf-8转码成utf-16。由fromUtf8()可知,QString需要执行字符集编码为utf-8,然后以utf-8进行解码,再编码为utf-16才能获得正确的字符编码。所以,显示中文乱码的原因为:QString的转码方式与执行字符集不一致。(比如,源文件字符集为本地字符集GBK编码,QString以utf-8的方式进行解码,会导致获得错误的二进制编码,再将错误二进制转为utf-16就会出现乱码。)

注意:
1.当Qt 5.11.3 MinGW 32bit编译程序的时候,会分析源代码文件采用何种编码,有BOM标识符则可以正确识别其编码,若没有BOM标识符则认为其使用本地字符编码local字符集。此处使用的windows 10的本地字符编码为GBK编码。
2.编译器分析出源文件字符编码之后,会进行解码再编码,将源字符集转码成执行字符集。执行字符集一般默认为使用本地字符编码local字符集,也可以进行设置。

中文乱码测试

在GUI应用程序的主函数里创建一个QString对象hello,因为QString构造函数内部调用了QString::fromUtf8(),所以hello和QString::fromUtf8(“中文”)的表现应该是一致的。QString::fromLocal8Bit()将执行字符集以本地编码转为utf-16。如下为具体代码:

#include "dialog.h"
#include <QApplication>

int main(int argc, char *argv[])
{
  QApplication a(argc, argv);
  Dialog w;
  w.show();

  QString hello="中文";
  qDebug()<<hello;
  qDebug()<<QString::fromUtf8("中文");
  qDebug()<<QString::fromLocal8Bit("中文");

  return a.exec();
}

例1:源文件代码的编码字符集为GB2312(Simplified),程序结果如下:
在这里插入图片描述
结果表明,前两种发生了乱码,fromLocal8Bit()显示正常。源代码文件的源文件代码的编码字符集为GB2312(Simplified),不带BOM标识,因此编译器会认为源代码文件的编码为操作系统的本地编码,而源代码文件的编码的确与本地编码一致,所以fromLocal8Bit显示正常。因为fromUtf8将执行字符集以utf-8进行解码,显示乱码。

例2:源文件代码的编码字符集为UTF-8,程序结果如下:
在这里插入图片描述结果表明,前两种显示正常,fromLocal8Bit()发生了乱码。源代码文件的源文件代码的编码字符集为UTF-8,不带BOM标识,因此编译器会认为源代码文件的编码为本地编码,执行字符集也是本地编码,因此不会进行转码,但实际上执行字符集是utf-8编码。因此fromUtf8将执行字符集以utf-8进行解码,显示正确;而fromLocal8Bit将执行字符集以本地编码进行解码,显示乱码。

解决方案

由于程序的源代码文件采用的编码方式是GB2312(Simplified),不带BOM标识,因此编译器会认为源代码文件的编码为操作系统的本地编码,而源代码文件的编码的确与本地编码一致,所以fromLocal8Bit显示正常。所以解决中文乱码问题的方法是:程序中凡是用到中文的地方都以QString::fromLocal8Bit(“中文”)的形式出现。如下为改进后的程序结果:
在这里插入图片描述

在这里插入图片描述

情况二

软件平台:Windows 10,Qt Creator 4.7.2,CMake 3.13.4

问题描述:运行一个含有中文输出的cmake项目时,在控制台中输出的都是中文乱码。出现中文乱码的原因在于,中文版的Windows平台支持的是GB2312的编码格式,而Qt Creator默认使用的则是Linux下通用的UTF-8编码格式,然后,基于Windows平台的程序控制台再用GB2312编码格式来解释本是UTF-8格式的中文输出,进而就因为两者的编码格式的不同导致了中文乱码的输出。解决问题的思路为,一是改变Windows系统的编码格式为UTF-8,二是把Qt Creator的默认编码格式改为GB2312。下面的解决方案遵循思路二。
在这里插入图片描述
解决方案:工具=>选项=>文本编辑器=>行为,把文件编码那一块中的默认编码设为:GB2312,然后点击Apply,再点击OK
在这里插入图片描述
把编辑器的默认编码改为GB2312后,还要注意一些事项才能输出中文,注意事项如下:

  • 把代码string a="你好,中文!";中的中文去掉,如string a="";,其他的也可以,只要保证代码中没有中文即可

  • 进入项目所在的目录,把构建目录build和项目文件CMakeLists.txt.user删除掉
    在这里插入图片描述

  • 通过Qt Creator打开文件CMakeLists.txt重新构建CMake项目HelloWorld,然后把之前的代码改回来,即把string a="";改为string a="你好,中文!";。如此,在控制台中输出的中文就不再是乱码了在这里插入图片描述

  • 8
    点赞
  • 33
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值