QT中文乱码的根本解决办法

本文详细介绍了解决QT中中文乱码的方法,包括设置字符集、处理文件读取中的乱码问题,以及如何通过QT提供的工具和技术实现软件的国际化支持。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

QT 官方文档:Qt Documentation | Home

下载与安装说明:https://zhuanlan.zhihu.com/p/622591698

在线安装程序qt-unified-windows-x64-online.exe 清华镜像地址:

Index of /qt/official_releases/online_installers/ | 清华大学开源软件镜像站 | Tsinghua Open Source Mirror

QT中文乱码的解  

今晚使用QMessageBox出现中文乱码,参考网上相关文档解决问题。下面这篇文章是从网上搜索的,文中说QTextCodec::codecForName("GB2312")等代码可以保证在程序中直接使用中文而不出现乱码是欠全面的,比如,在Mac OS X 10.6.2中文版上,须使用QTextCodec::codecForName("UTF-8")才能保证中文不出现乱码。

QT国际化支持

    Qt内部采用的全Unicode编码,这从根本上保证了多国语界面实现的正确性和便捷性。Qt本身提供的linguist工具,用来实现翻译过程十分方便。MFC中利用资源DLL切换资源,或使用多个RC文件进行不同语言版本编译等方法都十分麻烦,如果你曾经使用过MFC,QT解决多语言问题的便捷性绝对会让你感觉是一种享受。本文讨论以下几个方面内容:

1、  QT中解决中文乱码的方法;

2、  QT中实现国家化支持。

3、  对话框实现多语言

一、       中文乱码

1、  在程序中直接使用中文,需要在程序中加入以下代码:

  1. #include <QTextCodec>  
  2.   
  3. int main(int argc, char **argv)  
  4. {  
  5.            QApplication app(argc, argv);  
  6.            QTextCodec *codec = QTextCodec::codecForName("GB2312");  
  7.   
  8.            QTextCodec::setCodecForLocale(codec);  
  9.            QTextCodec::setCodecForCStrings(codec);  
  10.            QTextCodec::setCodecForTr(codec);  
  11.   
  12.            …… ……  
  13.             return app.exec();  
  14. }  

这样在程序中使用tr(“中文”)或者直接使用“中文”了;

2、  解决读取ini文件中中文乱码

QSettings settings("xxxx.ini",QSettings::IniFormat);

settings.setIniCodec(QTextCodec::codecForName("GB2312")); settings.beginGroup("company");

3、  解决读取中文文件中文的乱码

  1. QFile file("xxxx.txt");  
  2. QTextStream stream(file,QIODevice::ReadOnly);  
  3. stream.setCodeC( QTextCodec::codecForName("GB2312") );  
  4. stream.readAll();  

二、       国际化支持

QT中实现多国语言,建议在程序中直接英文,而后通过不同的翻译文件实现多语言的支持。实现多国语的步骤有如下几步(提及的工具均为QT自带):

?  在需要被翻译的字符串前面加标识tr,如QString str = tr(“hello,world!”); 这很重要,因为翻译工具会把源码中tr标识的字符串提取出来,翻译成其他语言,如果没有用tr标识的,不会被工具提取。在界面中输入的文字,默认已经是加上tr的了,所以在翻译时也能看见。

?  在QT工程文件*.pro中增加一项:TRANSLATIONS += *.ts,扩展名为.ts是翻译的源文件。一般会在命名中把区域加进去,更好的注释这些文件是用于什么语言的,可以根据“语言_国家”的形式形成文件名。比如中命名为myapp_zh_CN.ts, zh表示简体中文,而CN表示的就是中华人名共和国。可以参照ISO语言与国家代码标准:ISO语言代码(ISO-639)与国家代码(ISO-3166)_语言参数是 iso 代码-优快云博客

?  使用lupdate工具提取翻译源文件,【运行】中输入CMD,打开命令行窗口,利用CD命令切换到QT安装目录的BIN目录中,而后输入:

lupdate *.pro

*.pro包含pro文件的全路径。lupdate会解析*.pro文件,生成TRANSLATIONS中的 *.ts 文件,这些文件可以被linguist工具打开,按照提示一个一个的翻译成需要的文件并保存。

?  重复以上两步!
(针对以上两步,VS2005中可以直接使用菜单【QT】à 【Create new translations File】创建,如果文件已经存在,可以通过图1.1菜单进行更新。)

    

图1.1 VS2005_lupdate

?  使用lrelease工具发布翻译文件的二进制文件,这样在程序运行时载入会大大的加快速度。在命令行窗口中继续输入:

lrelease *.ts

*.ts包含ts文件的全路径。这个工具会提示你多少语句被翻译,多少被忽略了等。生成的文件是*.qm,与同名的 *.ts只是换了一个扩展名。这个就是我们程序需要使用到的文件。

(VS2005中可以使用图1.1中的菜单lrelease来实现该步骤)

?  使用*.qm文件。程序可以通过两种方式加载翻译文件,一种硬编码方式,直接指定加载的语言,代码如下:

int main(int argc,char* argv[])
{
         QApplication app(arcg,argv);
         QTranslator translator;
         translator.load(“basicdraw_zh_CN”);
         app.installTranslator(&translator);

}

另外一种是自动判断翻译当前的locale,再装入相应的翻译文件,如下所示:

int main(int argc,char* argv[])
{
         QApplication app(arcg,argv);
         QString locale = QLocale::system().name();
         QTranslator translator;
         translator.load(QString(“basicdraw_”) + locale);
         app.installTranslator(&translator);
}

其中QLocale::system().name()返回以“语言_国家”形式形成的字符串,比如zh_CN。

至于通过控件,比如ComboBox选择语言,并实现动态切换,以后再讨论。

三、       对话框实现多语言

在实际程序中实现多语言切换,需要生成的qm文件应该包含两个:

?  QT运行库相关的qm文件:在QT安装目录的translations目录下,存在需要*.ts文件,利用lrelease命令生成对应的qm文件。

?  利用“二”中的步骤生成程序本身需要的*.ts文件,并生成qm文件。

QApplication支持多个翻译文件,并根据后加入先使用的搜索顺序进行搜索。

具体代码如下:
main.cpp

  1. #include "stdafx.h"  
  2. #include <QtGui/QApplication>  
  3. #include <QtGui/QtGui>  
  4. #include "DialogLogin.h"  
  5.   
  6. int main(int argc, char *argv[])  
  7. {  
  8.     QApplication app(argc, argv);  
  9.     QTextCodec::setCodecForLocale(QTextCodec::codecForLocale());  
  10.   
  11.     // 安装QT运行库翻译器  
  12.     QTranslator translatorQT;  
  13.     {  
  14.         QStringList environment = QProcess::systemEnvironment();  
  15.         QString str;  
  16.         bool bFinded = false;  
  17.   
  18.         foreach(str, environment)  
  19.         {  
  20.             if(str.startsWith("QTDIR="))  
  21.             {  
  22.                 bFinded = true;  
  23.                 break;  
  24.             }  
  25.         }  
  26.   
  27.         if(bFinded)  
  28.         {  
  29.             str = str.mid(6);  
  30.             bFinded = translatorQT.load("qt_" + QLocale::system().name(),str.append("/translations/"));  
  31.   
  32.             if(bFinded)  
  33.                 app.installTranslator(&translatorQT);  
  34.             else  
  35.                 qDebug() <<QObject::tr("Can't find the translation file for Chinese!");  
  36.         }  
  37.         else  
  38.         {  
  39.             qDebug() << QObject::tr("Please set the environment variable QTDIR");  
  40.         }  
  41.     }  
  42.   
  43.     // 安装程序自身翻译器  
  44.     QTranslator translatorApp;  
  45.     {  
  46.         QString strLanguageDir = QCoreApplication::applicationDirPath();  
  47.         strLanguageDir.append("/Language/");  
  48.   
  49.         QString strFilePath = QApplication::applicationFilePath();  
  50.         QString strFileName = strFilePath.right(strFilePath.size() - strFilePath.lastIndexOf('/') - 1);  
  51.   
  52.         strFileName = strFileName.left(strFileName.indexOf('.'));  
  53.         strFileName.append('_');  
  54.         strFileName.append(QLocale::system().name());  
  55.         bool bFinded = translatorApp.load(strFileName,strLanguageDir);  
  56.   
  57.         if(bFinded)  
  58.             app.installTranslator(&translatorApp);  
  59.         else  
  60.         {  
  61.             qDebug() << QObject::tr("Can't Find The Translation's File For Chinese!");  
  62.         }  
  63.     }  
  64.   
  65.     CDialogLogin dlg;  
  66.   
  67.     return dlg.exec();  
  68. }  


DialogLogin.h

  1. #pragma once  
  2. #include <QtGui/QDialog>  
  3.   
  4. class QLineEdit;  
  5. class CDialogLogin : public QDialog  
  6. {  
  7.     Q_OBJECT  
  8.   
  9. public:  
  10.     CDialogLogin(QWidget* parent = 0);  
  11.     ~CDialogLogin(void);  
  12.   
  13. public slots:  
  14.     virtual     void    accept();  
  15.   
  16. private:  
  17.     QLineEdit*  m_pUsrLineEdit;  
  18.     QLineEdit*  m_pPwdLineEdit;  
  19. };  

程序中使用了两个QTranslator对象,在app利用函数installTranslator()进行翻译器安装时,并没有拷贝qm文件,而是在需要的时候在qm文件中进行查找。也即是说:QTranslator在load以后,并没有把qm文件中的数据拷贝一份。如果qm在这期间被删除或修改,对程序都是有影响的。扩展开来,QTranslator必须保证要一直有效,如果在函数中定义的局部变量,函数结束后就自动释放掉了,那么翻译工作就不能正常进行。
DialogLogin.cpp

  1. #include "stdafx.h"  
  2. #include "DialogLogin.h"  
  3. #include <QtGui/QtGui>  
  4.   
  5. CDialogLogin::CDialogLogin(QWidget* parent/* = 0 */)  
  6.     : QDialog(parent)  
  7. {  
  8.     QLabel* pUsrLabel = new QLabel(tr("User Name:"));  
  9.     QLabel* pPwdLabel = new QLabel(tr("Password:"));  
  10.   
  11.     m_pUsrLineEdit = new QLineEdit();  
  12.     m_pPwdLineEdit = new QLineEdit();  
  13.     m_pPwdLineEdit->setEchoMode(QLineEdit::Password);  
  14.   
  15.     QGridLayout* pGridLayout = new QGridLayout();  
  16.   
  17.     pGridLayout->addWidget(pUsrLabel,0,0,1,1);  
  18.     pGridLayout->addWidget(m_pUsrLineEdit,0,1,1,3);  
  19.     pGridLayout->addWidget(pPwdLabel,1,0,1,1);  
  20.     pGridLayout->addWidget(m_pPwdLineEdit,1,1,1,3);  
  21.     pGridLayout->setSpacing(25);  
  22.   
  23.     QPushButton* pBtnOK = new QPushButton(tr("Login"));  
  24.     QPushButton* pBtnCancel = new QPushButton(tr("Cancel"));  
  25.   
  26.     QHBoxLayout* pBtnLayout = new QHBoxLayout();  
  27.     pBtnLayout->setSpacing(60);  
  28.     pBtnLayout->addWidget(pBtnOK);  
  29.     pBtnLayout->addWidget(pBtnCancel);  
  30.   
  31.     QVBoxLayout* pDlgLayout = new QVBoxLayout();  
  32.     pDlgLayout->setMargin(30);  
  33.     pDlgLayout->addLayout(pGridLayout);  
  34.     pDlgLayout->addStretch(40);  
  35.     pDlgLayout->addLayout(pBtnLayout);  
  36.     pDlgLayout->setSpacing(40);  
  37.     setLayout(pDlgLayout);  
  38.   
  39.     connect(pBtnOK,SIGNAL(clicked()),this,SLOT(accept()));  
  40.     connect(pBtnCancel,SIGNAL(clicked()),this,SLOT(reject()));  
  41.   
  42.     setWindowTitle(tr("Login"));  
  43.     resize(300,200);  
  44. }  
  45.   
  46. CDialogLogin::~CDialogLogin(void)  
  47. {  
  48. }  
  49.   
  50. void CDialogLogin::accept()  
  51. {  
  52.     if(m_pUsrLineEdit->text().trimmed() == tr("lcf") && m_pPwdLineEdit->text().trimmed() == tr("lcf"))  
  53.     {  
  54.         QDialog::accept();  
  55.     }  
  56.     else  
  57.     {  
  58.         QMessageBox::warning(this,tr("Warning"),tr("User Name or Password is wrong!"),QMessageBox::Yes);  
  59.   
  60.         m_pUsrLineEdit->setFocus();  
  61.     }  
  62. }  


其中英文界面如图:

图1.2 英文界面


中文界面如图:

图1.3 中文界面

引用地址:

评论:

卡卡
约 18 小时前
    QTextCodec *codec = QTextCodec::codecForName("GB2312"); 
    QTextCodec::setCodecForLocale(codec); 
    QTextCodec::setCodecForCStrings(codec); 
    QTextCodec::setCodecForTr(codec); 

    if(n==0) 
        m_ui->label->setText(tr("<h1>黑方赢了!</h1>")); 
    if(n==1) 
        m_ui->label->setText(tr("<h1>白方赢了!</h1>"));
 

这程序在我电脑上显示正常,但在被人电脑上出现乱码,请问这是怎么回事啊?
博主回复:最可能的原因是,你的电脑上的本地字符集采用的是GB2312,而别人的电脑上采用的是别的字符集,例如UTF-8。你的代码中QTextCodec *codec = QTextCodec::codecForName("GB2312"); 
一句决定了在字符集为GB2312的电脑上能够正常显示,而在字符集为UTF-8的电脑上显示为乱码。

<think>好的,用户之前问过如何用QProcess打开带中文路径的软件,我给出了详细的解决方案。现在用户反馈说按照我的修改后,路径还是乱码。我需要仔细分析可能的原因,并给出有效的解决办法。 首先,我需要考虑用户的环境。用户可能使用的是Windows系统,因为中文路径在Windows下更容易出现编码问题。QProcess在Windows下处理路径时,需要将Unicode路径转换为系统本地编码,通常是GBK。用户可能没有正确进行编码转换,或者转换方法有误。 接着,用户提到的“路径还是乱码”,可能指的是程序启动失败,或者启动的程序无法正确读取参数中的中文路径。需要分情况讨论:是QProcess无法找到可执行文件,还是可执行文件本身在处理参数时出现乱码? 我需要回顾之前的解决方案,确认是否有遗漏的步骤。之前的回答中提到了使用QDir::toNativeSeparators和QString::fromLocal8Bit(path.toLocal8Bit())来处理路径。但可能用户在某些情况下没有正确应用这些步骤,比如路径中包含空格,或者参数中的中文没有处理。 另外,用户可能没有正确设置工作目录,或者可执行文件本身需要特定的环境变量。例如,如果程序依赖某些DLL文件,而工作目录不正确,可能导致启动失败,但用户可能误认为是路径乱码问题。 可能的错误点包括: 1. 路径转换不正确:虽然使用了toLocal8Bit,但可能系统编码不是GBK,或者转换步骤有误。 2. 参数处理遗漏:如果启动程序时带有中文参数,这些参数也需要同样进行编码转换。 3. 路径存在空格:虽然之前的回答提到不要手动加引号,但用户可能在路径中包含空格,而QProcess没有正确解析。 4. 文件权限或路径存在特殊字符:比如路径中包含特殊符号,导致系统无法识别。 5. 同步执行与异步执行的区别:用户可能使用了start()但没有正确处理进程输出,导致错误信息未被捕获。 我需要进一步询问用户具体的代码示例,或者提供更详细的排查步骤。例如,建议用户打印处理后的路径的本地编码字节,确认是否正确转换为GBK。或者检查文件是否存在,权限是否正确。 另外,可能需要考虑不同版本的Qt在处理路径时的差异。例如,Qt5和Qt6在编码处理上是否有不同,是否需要使用特定的QTextCodec。 总结可能的解决方案: 1. 确认路径转换正确,使用QDir::toNativeSeparators和fromLocal8Bit。 2. 检查参数中的中文是否同样处理。 3. 验证路径是否存在,权限是否正确。 4. 使用QFileInfo检查文件是否存在。 5. 输出调试信息,确认转换后的路径是否正确。 6. 处理工作目录,特别是当路径包含空格或特殊字符时。 7. 考虑系统区域设置是否支持中文路径。 可能需要分步骤指导用户进行排查,例如: - 打印处理后的路径,检查是否包含正确的反斜杠。 - 使用QFile::exists验证路径是否有效。 - 输出本地编码的十六进制,确认是否转换为正确的GBK字节。 另外,可能需要提醒用户,某些安全软件可能会阻止进程的启动,导致失败,但这通常不会显示为路径乱码问题。 最终,需要给出一个结构化的解决方案,分点列出可能的原因和对应的解决方法,帮助用户逐步排查问题。</think>当路径处理后仍出现乱码时,请按照以下步骤深度排查与解决: --- ### **一、核心问题定位** #### 1. **区分错误类型** - ❌ **启动失败**:程序根本未启动(路径转换错误) - ❌ **程序内部乱码**:程序已启动但读取参数错误(参数编码问题) #### 2. **快速验证方法** ```cpp // 在代码中添加调试输出 qDebug() << "原始路径:" << rawPath; qDebug() << "处理后路径:" << processedPath; qDebug() << "本地编码字节:" << processedPath.toLocal8Bit().toHex(); qDebug() << "文件是否存在:" << QFile::exists(processedPath); ``` --- ### **二、Windows 系统专项排查** #### **1. 编码验证(关键)** - **正确转换应满足**: ```cpp QString path = "D:/测试/中文目录/app.exe"; // 正确转换后的GBK字节示例(十六进制) qDebug() << path.toLocal8Bit().toHex(); // 应输出类似 "443a5c2d4b845c...exe" 的GBK编码 ``` - **修复方案**: ```cpp // 强制转换为GBK编码(兼容所有Qt版本) QTextCodec *gbkCodec = QTextCodec::codecForName("GB18030"); QString safePath = gbkCodec->toUnicode(gbkCodec->fromUnicode(path)); ``` #### **2. 特殊符号处理** - **空格路径必须保留原始结构**: ```cpp // 错误:手动添加引号 process.setProgram("\"C:/Program Files/我的软件/app.exe\""); // 正确:依赖QProcess自动处理 process.setProgram("C:/Program Files/我的软件/app.exe"); ``` #### **3. 系统权限问题** ```cpp QFileInfo info(path); if(!info.exists()) { qDebug() << "路径不存在"; } else if(!info.isExecutable()) { qDebug() << "无执行权限"; QFile::setPermissions(path, QFile::ExeUser | QFile::ReadUser); } ``` --- ### **三、跨平台兼容处理** ```cpp QString safePath(const QString &path) { QString p = QDir::toNativeSeparators(QDir::cleanPath(path)); #ifdef Q_OS_WIN // Windows强制转换为ANSI路径 wchar_t buffer[MAX_PATH]; if(QDir::toNativeSeparators(p).toWCharArray(buffer) > 0) { return QString::fromWCharArray(buffer); } #endif return p; } // 使用示例 QProcess::startDetached(safePath("D:/测试/程序.exe")); ``` --- ### **四、参数传递乱码处理** 当**程序已启动但参数乱码**时: ```cpp QStringList args; args << "中文参数.txt"; #ifdef Q_OS_WIN // Windows参数需单独转换 QTextCodec *gbk = QTextCodec::codecForName("GBK"); QStringList gbkArgs; foreach(const QString &arg, args) { gbkArgs << gbk->toUnicode(arg.toLocal8Bit()); } process.setArguments(gbkArgs); #else process.setArguments(args); #endif ``` --- ### **五、终极调试方案** #### **1. 直接调用CMD验证** ```cpp // 生成调试命令 QString cmd = QString("cmd /c \"\"%1\" \"%2\"\"") .arg(exePath) .arg("测试参数.txt"); // 显示实际执行的命令 qDebug() << "CMD命令:" << cmd; // 执行并捕获输出 QProcess::execute("cmd", {"/c", cmd}); ``` #### **2. 使用Win32 API验证** ```cpp #include <windows.h> QString path = "D:/测试/app.exe"; STARTUPINFOW si = {0}; PROCESS_INFORMATION pi = {0}; // 转换为Windows宽字符路径 wchar_t *wPath = new wchar_t[path.length()+1]; path.toWCharArray(wPath); wPath[path.length()] = 0; if(CreateProcessW(NULL, wPath, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi)) { qDebug() << "Win32启动成功"; } else { qDebug() << "Win32错误码:" << GetLastError(); } ``` --- ### **六、典型错误案例** #### **案例1:Qt版本差异** - **Qt5**:默认使用`QTextCodec`转换 - **Qt6**:需手动添加编码支持: ```bash # 在pro文件中添加 QT += core5compat ``` #### **案例2:路径拼接错误** ```cpp // 错误:直接字符串拼接 QString path = QCoreApplication::applicationDirPath() + "/中文子目录/app.exe"; // 正确:使用QDir组合路径 QString path = QDir(QCoreApplication::applicationDirPath()) .filePath("中文子目录/app.exe"); ``` --- ### **七、高级技巧** #### **1. 注册表验证文件关联** ```cpp // 检查.exe文件的默认打开方式 QString extension = ".exe"; QString regPath = "HKEY_CLASSES_ROOT\\" + extension; QSettings reg(regPath, QSettings::NativeFormat); QString handler = reg.value("Default").toString(); qDebug() << "EXE文件关联:" << handler; ``` #### **2. 使用短路径名称** ```cpp // 获取DOS 8.3短路径(规避长路径问题) wchar_t shortPath[MAX_PATH]; if(GetShortPathNameW(wPath, shortPath, MAX_PATH) > 0) { QString dosPath = QString::fromWCharArray(shortPath); qDebug() << "短路径:" << dosPath; } ``` --- 通过以上步骤的系统排查,可准确定位以下问题: - 编码转换未生效(需验证`toLocal8Bit()`输出) - 路径存在隐藏字符(如UTF-8 BOM头) - 防病毒软件拦截(临时关闭测试) - 系统区域设置非中文(控制面板 → 区域 → 管理 → 非Unicode程序语言) 建议逐项执行验证,并在每个步骤后添加调试输出,以精确锁定问题根源。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值