Qt 5 中文显示问题

木头r 发布于 2013/04/03 21:15
阅读 24K+
收藏 1

Qt更新了最新版本5.0.1,可是对中文显示问题一直没弄清楚。

1.不管源代码(cpp)文件是unicode还是utf8还是ascii格式,只要是中文字符串,都无法正常显示。

2.如果使用国际化,tr("中文"),也是无法显示,就算添加下面的代码,也还是无法显示。

QTextCodec::setCodecForLocale(QTextCodec::codecForName("gbk"));


对于1,如果使用下面代码,则可以正常显示

QString::fromLocal8Bit("中文")


请熟悉的朋友给予解答,该怎么来使用Qt显示中文?(是在Qt5.0.1版本,VS2010或者Qt creator)。








以下是问题补充:

@木头r:Qt Creator无法显示中文的问题已经找到答案了: 如果Qt Creator创建的源文件是带BOM的utf8格式,则无法正常显示中文。 必需是不带BOM的utf8格式。 (2013/04/04 00:13)
加载中
1
chai2010
chai2010
要搞清楚这个问题,先要弄明白编码。但是编码问题实在太复杂,这里肯定讲不开。

我先找一个例子,比如:"中文" 的 Unicode 码点/UTF8编码/GBK 分别是多少。

先去这个网站,输入 "中文" 查询对应的 Unicode 码点/UTF8编码:
http://www.mytju.com/classcode/tools/encode_utf8.asp

Unicode的码点分别是(十进制):中(20013),文(25991)。
对应的UTF8编码分别(16进制): 中(E4B8AD),文(E69687)。

然后再去下面这个网站,输入 "中文" 查询对应的 GBK 编码:
http://www.mytju.com/classcode/tools/encode_gb2312.asp

GBK编码16进制(GBK内码)分别是:中(D6D0),文(CEC4)。

现在已经知道了"中文"的UTF8和GBK编码的具体值。
我们再看看VC2010是怎么处理的。

1. 先看 无 BOM 的 UTF8 编码的代码 (utf8_no_bom.cpp)

// utf8 no bom
// 文件中包含不能在当前代码页(936)中表示的字符
#include <stdio.h>

int main() {
    const char* str = "中文";
    for(int i = 0; i < sizeof(str); ++i) {
        printf("0x%x ", str[i]&0xFF);
    }
    return 0;
    // Output:
    // 0xe4 0xb8 0xad 0xe6
}
输出是:0xe4 0xb8 0xad 0xe6。
感觉好像是对的。

但是,先别急:VC编译时输出了一条警告信息:
utf8_no_bom.cpp : warning C4819: 该文件包含不能在当前代码页(936)中表示的字符。
请将该文件保存为 Unicode 格式以防止数据丢失。

潜台词就是,你这个代码有GBK不能表示的字符,请用Unicode方式保存。
VC根本就没把 代码(utf8_no_bom.cpp) 当作UTF8,VC只是把它作为GBK处理罢了。

那为什么又输出了正确的结果呢?

因为 VC 把 (utf8_no_bom.cpp) 当作 GBK,而编译时也要转换为本地编码(也是GBK)。因此,UTF8编码的 "中文",被VC当作编码GBK编码的 "0xe4 0xb8 0xad 0xe6" 的字符串处理了(肯定不是"中文"含义了)。


VC已经不知道 "0xe4 0xb8 0xad 0xe6" 是对应 "中文" 字面值了。

但是在GBK(实际是无BOM的UTF8)转GBK的过程中,发现了一些UTF8编码的字符并不是GBK能表达的合理方式,因此就出现了那个C4819编译警告。

2. 再看带BOM的UTF8是怎么处理的 (utf8_with_bom.cpp)

// utf8 with bom
#include <stdio.h>

int main() {
    const char* str = "中文";
    for(int i = 0; i < sizeof(str); ++i) {
        printf("0x%x ", str[i]&0xFF);
    }
    return 0;
    // Output:
    // 0xd6 0xd0 0xce 0xc4
}


编译没有警告,但是输出有问题:0xd6 0xd0 0xce 0xc4。

源文件明明是 UTF8 编码的格式"0xe4 0xb8 0xad 0xe6",
怎么变成了 "0xd6 0xd0 0xce 0xc4" (这个是GBK编码)?

这就是VC私下干的好事:它自作聪明的将UTF8源代码转换为GBK处理了!

VC为何要做这样蠢事?

原因是为了兼容老的VC版本。
因为以前的VC不能处理UTF8,都是用本地编码处理的。

3. 在看看真的GBK是怎么处理的 (gbk.cpp)

// gbk
#include <stdio.h>

int main() {
    const char* str = "中文";
    for(int i = 0; i < sizeof(str); ++i) {
        printf("0x%x ", str[i]&0xFF);
    }
    return 0;
    // Output:
    // 0xd6 0xd0 0xce 0xc4
}
没有编译错误,输出也和源代码一致:"0xd6 0xd0 0xce 0xc4"。

因为源文件就是GBK,cl在编译时GBK转化为GBK,没有改变字符串。

只是,现在很多人不想用GBK了(因为只能在中国地区用,不能表示全球字符)。

------

到这里,可以初步小结一下:

1. VC编辑器和VC编译器是2个概念,VC编辑器支持UTF8并不能表示VC编译器也支持UTF8
2. VC编辑器从2008?开始支持带BOM的UTF8(不带BOM的暂时没戏,因为会本地编码冲突)
3. VC编译器从2010开始也可以支持UTF8了(虽然支持方式很不优雅)

------

继续前面的测试,

看看VC2010编译器是怎么支持带BOM的UTF8的 (utf8_with_bom_2010.cpp)

// utf8 with bom (VC2010), 下面这句是重点!
#pragma execution_character_set("utf-8")

#include <stdio.h>

int main() {
    const char* str = "中文";
    for(int i = 0; i < sizeof(str); ++i) {
        printf("0x%x ", str[i]&0xFF);
    }
    return 0;
    // Output:
    // 0xe4 0xb8 0xad 0xe6
}
没有编译错误,输出也和源代码一致:"0xe4 0xb8 0xad 0xe6"。

UTF8编码,UTF8输出。完美!

------

回到 Qt5 的中文输出问题。

Qt默认支持 VS2010/MinGW/Gcc 等编译器,而它们现在都已经真正支持UTF8了。

当然,VS2010 对UTF8的支持会入侵代码(#pragma execution_character_set("utf-8"))。

看看Qt官方论坛别人是怎么说的:
http://qt-project.org/forums/viewthread/17617

Nothing special need to do, it will works by default.
If the exec-charset of your your compiler is UTF-8.

简单的说,从Qt5开始,源代码就是默认UTF8编码的。

当然,VC2010编辑器对带BOM的UTF8也是认识,只可惜VC2010编译器根本人认识!

在继续看官方论坛的回复:
You can write a simple example like this

#include <QApplication>
#include <QLabel>
 
#if _MSC_VER >= 1600
#pragma execution_character_set("utf-8")
#endif
 
int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QLabel label("ąśćółęńżź");
    label.show();
 
    return a.exec();
}

If other people can reproduce your problem, you can file a bug.

就是我之前贴的代码。只不过我贴的代码增加了Qt4/Qt5和非VC环境的判断。

当然,如果你要是不相信,那我也没什么可说的了...


PS: 此文已经放到我 @chai2010 的博客了(以后有时间再完善):

http://my.oschina.net/chai2010/blog/119833

0
kb程序员
kb程序员

qt5的中文和英文是一样的用,不需要特殊处理。

看看是不是没有中文字体。

0
kb程序员
kb程序员
楼主是在pc上还是在嵌入式。前段时间qt5在arm上触摸屏没搞定
0
chai2010
chai2010

Qt5好像只认UTF8了。

对于VC,即使源代码是带BOM的UTF8,编译时好像还是会转换为本地编码。

如果是VC2010,可以用 execution_character_set 选项强制启用UTF8编码:

// Coding: UTF-8
#pragma execution_character_set("utf-8")

Qt5的代码不用设置编码。不过为了和Qt4兼容,可以加入以下代码:

#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
    #if defined(_MSC_VER) && (_MSC_VER < 1600)
        QTextCodec::setCodecForTr(QTextCodec::codecForName("GB18030-0"));
    #else
        QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
    #endif
#endif
当然源代码建议是带BOM的UTF8,并且包含 `#pragma execution_character_set("utf-8")` 选项。
0
木头r
木头r

引用来自“张某人某人”的答案

qt5的中文和英文是一样的用,不需要特殊处理。

看看是不是没有中文字体。

在windows上使用,肯定是有中文字体啊,

使用下面代码都可以正常显示中文

QString::fromLocal8Bit("中文")
而且ui文件自动生成的.h中的中文(用8进制转换了)都可以正常显示。

0
木头r
木头r

引用来自“张某人某人”的答案

楼主是在pc上还是在嵌入式。前段时间qt5在arm上触摸屏没搞定
pc上使用
0
chai2010
chai2010

引用来自“木头r”的答案

引用来自“张某人某人”的答案

qt5的中文和英文是一样的用,不需要特殊处理。

看看是不是没有中文字体。

在windows上使用,肯定是有中文字体啊,

使用下面代码都可以正常显示中文

QString::fromLocal8Bit("中文")
而且ui文件自动生成的.h中的中文(用8进制转换了)都可以正常显示。

ui生成的UTF8是用C语言的转义字符实现的,VC不会私下做手脚,因此是能显示的。
0
木头r
木头r

引用来自“chai2010”的答案

Qt5好像只认UTF8了。

对于VC,即使源代码是带BOM的UTF8,编译时好像还是会转换为本地编码。

如果是VC2010,可以用 execution_character_set 选项强制启用UTF8编码:

// Coding: UTF-8
#pragma execution_character_set("utf-8")

Qt5的代码不用设置编码。

不过为了和Qt4兼容,可以加入以下代码:

#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
    #if defined(_MSC_VER) && (_MSC_VER < 1600)
        QTextCodec::setCodecForTr(QTextCodec::codecForName("GB18030-0"));
    #else
        QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
    #endif
#endif
当然源代码建议是带BOM的UTF8,并且包含 `#pragma execution_character_set("utf-8")` 选项。

你的意思是只要源代码文件是带BOM的utf8,就可以正常显示中文?

可是我用Qt creator生成的工程也一样无法显示啊,源代码文件就是带BOM的utf8。

而且Qt5中已经没有setCodecForTr了啊。

FBWFBI
FBWFBI
你说的“Qt creator生成的工程”,对应的是MinGW的版本吧(gcc编译器),如果是这样的话,那就需要是不带BOM的utf-8编码;如果配置的是vc2010的编译器,那就必须要是带BOM的且包含了#pragma execution_character_set("utf-8") 这种预处理的源文件
0
chai2010
chai2010

带BOM的UTF8只能让VC看着不会出现中文乱码。

但是编译时,好像还是会将源文件转换为本地编码的。

对于VC2010或者更新版本的VC关键是要包含:

#pragma execution_character_set("utf-8")

当然,如果没有非英文的字符串,包不包含就没影响了。

完整的例子(Qt5/VC2010):

// Coding: UTF-8(BOM)
#if defined(_MSC_VER) && (_MSC_VER >= 1600)
# pragma execution_character_set("utf-8")
#endif

#include <QApplication>
#include <QTextCodec>
#include <QLabel>

int main(int argc, char* argv[])
{
    QApplication app(argc, argv);

#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
  #if defined(_MSC_VER) && (_MSC_VER < 1600)
    QTextCodec::setCodecForTr(QTextCodec::codecForName("GB18030-0"));
  #else
    QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8"));
  #endif
#endif

    QLabel *label = new QLabel(QObject::tr("你好!"));
    label->show();

    return app.exec();
}

0
sToa
sToa
可以试试下面的代码
void Global::setCodec(char *codeName)
{
        QTextCodec *codecs = QTextCodec::codecForName(codeName);
        if (NULL == codecs)
                codecs = QTextCodec::codecForLocale();

        QTextCodec::setCodecForLocale(codecs);
        QTextCodec::setCodecForTr(codecs);
        QTextCodec::setCodecForCStrings(codecs);
        
}


Global::setCodec("GB18030");


返回顶部
顶部