qt 中文乱码

初学Linux,直接进阶QT编程。然而,第一个Demo程序就碰到了中文乱码,巨汗! 
环境:

1、RedHat AS5

2、QT4.4.0

3、LANG="zh_CN.GB18030"

程序:

...

QTextCodec::setCodecForTr(QTextCodec::codecForName("gb18030"));

...

label.setText(QObject::tr("同一个世界,同一个梦想!"));

...

结果:

标题显示正常,标签和按钮的中文都是乱码。

网上搜索了3~4天,概括如下:

1、使用setDefaultCodec进行设置;

qApp->setDefaultCodec( QTextCodec::codecForName("GBK") );

QLabel *label = new QLabel( tr("中文标签") );

可惜setDefaultCodec是QT3的函数,QT4已经不支持了。

2、 设置QObject的成员函数tr()的编码;

QTextCodec::setCodecForTr(QTextCodec::codecForName("GBK"));

3、使用QString的fromLocal8Bit()函数;

QString str;

str = str.fromLocal8Bit("哈哈哈");

hello.setWindowTitle(str);

4、用QTextCodec的toUnicode方法来显示中文

QLabel hello(QObject::tr("你好").toLocal8Bit());

QTextCodec *codec = QTextCodec::codecForLocale();

QString a = codec->toUnicode("安师大手动");

以上各种都没有解决问题。

继续没有搜索这个问题,终于在一个blog中发现了真正的答案:字库问题。

“QT4下发现一个很奇怪的现象,就是对话框的Title“我是对话框”可以正确显示,而按钮就是小方块。总感觉是系统某些设置不对,而不是字符编码的问题,如果是字符编码问题,那么应该是乱码而不是小方块。忽然想到网上有提到过是字库的问题,觉得现象可以解释,标题栏和按钮文字不是同一种字体,而恰好按钮字体没有,所以是小方块,而不是乱码。

网上搜了下QT4用的默认字体,没有查到,又看了QT4的源代码,代码太多,也没有找到。

不过setFont函数引起了我的注意,在网上看到过这种方法。”

参考上面的内容,修改代码:

...

QTextCodec::setCodecForTr(QTextCodec::codecForName("gb18030"));

QFont font("Times",12,QFont::Normal,FALSE);

app.setFont(font);

...

label.setText(QObject::tr("同一个世界,同一个梦想!"));

...

成功!显示中文正常!

这个问题的解决真是太重要了,说实话真的有点疲惫,幸好没有放弃。yeah!

后记:使用qt的designer时,发现界面还是乱码。使用qtconfig设置font为Bitstream Charter后解决乱码问题。此时,我想原来的程序是不是也OK?不料一试,果然没有乱码~Oh MyGod!
 
Come From:http://www.linuxdiyf.com/viewarticle.php?id=97025 
另外的解决方案:

QTextCodec::codecForName(“GBK”)将返回NULL指针。

QTextCodec * BianMa = QTextCodec::codecForLocale();   //QTextCodec::codecForName ( "GBK" );

QT中文显示 收藏 
< type="text/javascript"> < type="text/javascript"> 
在QT中可以直接QTextCodec来转换字符串的编码,这为在QT下开发中文软件带来了便利条件,不过这种方法不符合国际化/本地化的标准:
CODE:
char *string = "你好,世界!";
QTextCodec *codec = QTextCodec::codecForName("GBK");
//QTextCodec *codec = QTextCodec::codecForName("Big5");
QString strText = codec->toUnicode(string);
QLabel *label = new QLabel(strText);

最直接的方法是把整个应用程序的编码设置为GBK编码,然后在字符串这前加tr:
CODE:
qApp->setDefaultCodec( QTextCodec::codecForName("GBK") );
...
QLabel *label = new QLabel(tr("你好,世界!"));

例:
CODE:
#include
#include
#include                         //文件头

int main( int argc, char *argv[] )
{
QApplication app( argc, argv );
app.setDefaultCodec( QTextCodec::codecForName("GBK") );
QLabel label(tr("你好,世界!"), NULL);
app.setMainWidget(&label);
label.show();
return app.exec();
}

如果使QT根据Locale的环境变量取得字符集,可以使用如下命令:
QString::fromLocal8Bit("你好,世界!");
例:
CODE:
#include
#include

int main( int argc, char *argv[] )
{
QApplication app( argc, argv );
QLabel label(QString::fromLocal8Bit("你好,世界!"), NULL);
app.setMainWidget(&label);
label.show();
return app.exec();
}
-------------------------------------------------------------------------------------------

法二:

QTextCodec::setCodecForTr(QTextCodec::codecForLocale());
-----------------------------------------------------------------------------------------
法三:可以写个函数
QString   init_gbk(QString s)
{
    QGbkCodec* gbk=(QGbkCodec*)QTextCodec::codecForName(\"GBK\"); 
    return gbk->toUnicode(s.latin1(),s.length()); 
}
调用下就好


QT中文文件

学点东西才是正道的   2008-08-23 17:00   阅读85   评论0   
字号: 大 大   中 中   小 小 
    虽然C++标准中有了文件读取的相关类,也很好用,但是在涉及到QT编程的时候却用起来不方便了,因为QT本身很多组件都是关联的自身的QString类型的字符串,所以再用C++本身String类型的时候就不是那么方便了,需要进行转化,这样给程序带来了复杂度,同时也带来了转化的开销,所以如果用 QT开发,可以就用它本身所带的这些类型进行处理,形成一个系统,便于数据在程序之中的交互和共用。
    QT很好,但是在处理中文或者其他语言的时候要注意编码格式,如果没有注意,读取文件的时候可能读出来的就是乱码或者干脆程序就死掉了,这是我们所不愿意看到的,下面就讲讲怎么样通过QT的类来读取中文文件。

介绍部分
    我们需要用到几个头文件中的类:
#include
#include
#include
#include


QString

QString类提供了一个Unicode文本和经典的C以零结尾的字符数组的抽象。 
QString使用隐含共享,这使它非常有效率并且很容易使用。 
所有的QString的方法都使用const char *参数,const char *被解释为经典的C风格的以零结尾的ASCII字符串。所以const char *参数为0是合法的。如果const char *不是以零结尾的,结果是不确定的。把经典的C字符串复制到QString的函数将不会复制结尾的0字符。QString的QChar数组(可以通过 unicode()返回)通常不以零结尾。如果你需要把QString传递到一个需要C的以零结尾的字符串,请使用latin1()。 
没有分配任何东西的QString是零,也就是长度和数据指针都为0。引用空字符串(“”,一个单一的'\0'字符)的QString是空。零和空这两个 QString在方法中都是合法的。把(const char *) 0赋值给QString给定了一个零QString。为了方便,QString::null是一个零QString。当排序的时候,空字符串在最前面,然后是非空字符串,然后才是零字符串。我们建议使用if ( !str.isNull() ),而不是if ( !str )来检测非零字符串,关于解释说明也可以参考operator!()。 
注意如果你发现你正在混合使用QCString、QString和QByteArray,这将会导致很多不必要的复制并且也许会预示着你正在处理的真实自然数据是不确定的。如果数据是以零结尾的八位数据,请使用QCString;如果它是没有结尾的(也就是包含0)八位数据,请使用QByteArray;如果它是文本,请使用QString。 
字符串列表可以使用QStringList类来处理。你可以使用QStringList::split()来把一个字符串分割为一个字符串列表,并且可以使用QStringList::join()把一个字符串列表连接成一个使用随意间隔符的字符串。你也可以使用QStringList::grep()从一个字符串列表中获得包含特定子字符串或者包含匹配特定的regex的字符串列表。 
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
QFile

QFile类是一个操作文件的输入/输出设备。 
QFile是用来读写二进制文件和文本文件的输入/输出设备。QFile可以自己单独被使用,但是如果和QDataStream或QTextStream一起使用将更加方便。 
文件名通常可以通过构造函数来传递,但也可以使用setName()来设置。你可以通过exists()来检查一个文件是否存在并且可以通过remove()来移去一个文件。 
文件可以用open()来打开、用close()来关闭、用flush()来刷新。数据通常可以使用QDataStream或者QTextStream进行读写,但你也可以使用readBlock()和readLine()来读,使用writeBlock()来写。QFile也支持getch()、 ungetch()和putch()。 
size()可以返回文件的大小。你可以通过使用at()函数得到当前文件位置或者移到一个新的文件位置。如果你到了文件的末尾,atEnd()返回真。handle()返回文件句柄。 
这里是一个使用QTextStream来一行一行地读取一个文本文件的代码段。它会把每一行带上一个行号打印出来。

    QStringList lines;
    QFile file( "file.txt" );
    if ( file.open( IO_ReadOnly ) ) {
        QTextStream stream( &file );
        QString line;
        int n = 1;
        while ( !stream.eof() ) {
            line = stream.readLine(); // 不包括“\n”的一行文本
            printf( "%3d: %s\n", n++, line.latin1() );
            lines += line;
        }
        file.close();
    }

写文本也很容易(假设我们有一个行的字符串列表要写):

    QFile file( "file.txt" );
    if ( file.open( IO_WriteOnly ) ) {
        QTextStream stream( &file );
        for ( QStringList::Iterator it = lines.begin(); it != lines.end(); ++it )
            stream << *it << "\n";
        file.close();
    }
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// 
QTextStream

QTextStream类提供了使用QIODevice读写文本的基本功能。 
文本流类的功能界面和标准的C++的iostream类非常相似。iostream和QTextStream的不同点是我们的流操作在一个很容易被继承的QIODevice上,而iostream只能操作一个不能被继承的FILE *指针。 
Qt提供了几个和iostream相似的全局函数: 
bin设置QTextStream来读/写二进制数字 
oct设置QTextStream来读/写八进制数字 
dec设置QTextStream来读/写十进制数字 
hex设置QTextStream来读/写十六进制数字 
endl强制换行 
flush强制QIODevice刷新任何被缓存的数据 
ws作为任何可用的控制符(在输入的时候) 
reset重新设置QTextStream为它的缺省模式(请见reset()) 
qSetW(int)设置字段宽度作为指定参数 
qSetFill(int)设置填充字符作为指定参数 
qSetPrecision(int)设置精确度作为指定参数 
警告:默认情况下,QTextStream在读取流的时候,会自动地检测流中的数字是十进制、八进制、十六进制或者二进制格式。具体情况是,一个以“0”为开头的数字是八进制的,比如顺序为“0100”将会被解释为64。 
QTextStream类读写文本,它不适合处理二进制数据(而QDataStream是适合的)。 
默认情况下,输出的是使用本地8位编码后的Unicode文本(比如,QString)。这些可以使用setEncoding()方法进行改变。对于输入,QTextStream会自动检测标准Unicode“字节顺序标记的”文本文件,否则会使用本地8位编码。 
QIODevice在构造函数中被设置,或者之后在setDevice()中使用。如果输入到达了atEnd(),返回真。数据可以使用 operator>>()重载操作符读到适当类型的变量中,或者使用read()把它作为整个部分读到一个单一的字符串中,或者使用 readLine()把一次读一行。使用skipWhiteSpace()可以忽略控制符。你可以使用flags()或setf()来设置流的标记。这个流也支持width()、precision()和 fill(),使用reset()可以重新恢复默认设置。 
也可以参考QDataStream、输入/输出和网络和文本相关类.
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

QTextCodec

QTextCodec 类提供文本编码之间的转换。
QT使用Unicode来存储,绘制以及操作字符串。在很多情况下,你可能想要使用不同的编码方式来处理数据。例如大部分的日语文件都被存储在 Shift-JIS或者 ISO2022的文件中,而俄罗斯的用户常常使用KOI8-R或者CP1251编码方式。QT提供了一个QTextCodec 类集合来从Unicode格式转化到相应的格式。

/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

代码部分

#include
#include
#include
#include

int main() 
{   
QFile file("test.txt");
if (file.open(IO_ReadOnly|IO_Raw))
{
   QTextStream floStream(&file);
   QString line;
   QTextCodec *codec=QTextCodec::codecForName("GBK");
   floStream.setCodec(codec); 
   while ( floStream.atEnd()==0 ) 
   {
    line = codec->fromUnicode(floStream.readLine()); 
    qWarning(line);
   }
   file.close();     
}
return 0;
}
代码中的主要改动就是黄底的部分
意思就是创立一个中文GBK编码样式,然后按照这种方式来把读入的文件流进行重新编码,这样中文就可以顺利输出了,不信你可以试一试

补上这两句就可以了显示中文了
#include  
QTextCodec::setCodecForTr(QTextCodec::codecForName("GB2312")) ;

谈谈Qt的中文编码~ 
  
 
来源: ChinaUnix博客  日期: 2009.07.04 11:23 (共有1 条评论) 我要评论  
 

原文链接:
http://www.cuteqt.com/blog/?p=531 
我的中文为什么没法显示?在Qt使用中经常有朋友会碰到这样的问题。
通过google搜索,会发现已经有人解决过了,无非就是重新设置一下默认的编码器
先调用下面两个函数之一
QTextCodec *textc=QTextCodec::codecForName(”gbk”);
QTextCodec *textc=QTextCodec::codecForName(”utf8″);
然后调用下面3个函数之一
QTextCodec::setCodecForCStrings(textc);
QTextCodec::setCodecForTr(textc);
QTextCodec::setCodecForLocale(textc);
至于调用哪一个是不知道的,只好挨着试,反正组合也不多。问题是解决了。但下次还是这么试。
下面我们来看看这几个函数都作用在什么地方。
1. setCodecForCStrings(textc)
这个函数主要用在用字符常量或者QByteArray构造QString对象时使用的默认编码方式。比如下面一个例子
23 int main(int argc,char *argv[]){
24     QApplication app(argc,argv);
25
26     QTextCodec *tc=QTextCodec::codecForName(”utf8″);
27     QTextCodec::setCodecForCStrings(tc);
28     QString str(”宁愿看见两个恶魔在拔河,也不愿看见一只天使在跳舞。”);
29     QPushButton ww(str);
30     ww.show();
31
32     app.exec();
33 }
如果把26,27行的地方注释掉,那么我们在QPushButton上看到的将是一堆乱码。因为在默认情况下QString把构造函数的字符串参数当成标准拉丁字符,很显然是会出现乱码的。如果是在Linux下的话你在编辑器里输入的时候,默认文本格式是”utf8″,如果你是在windows下做开发那么26行的地方很可能要改成”gbk”了。
2.  setCodecForTr(textc)
这个函数的作用是设置传给tr函数时的默认字串编码
23 int main(int argc,char *argv[]){
24     QApplication app(argc,argv);
25
26     QTextCodec *tc=QTextCodec::codecForName(”utf8″);
27     QTextCodec::setCodecForCStrings(tc);
28     QString str(QObject::tr(”宁愿看见两个恶魔在拔河,也不愿看见一只天使在跳舞。”));
29     QPushButton ww(str);
30     ww.show();
31
32     app.exec();
33 }
同样一个例子,我在28行的地方加了tr之后,运行的结果又不能正常显示中文了。需要将27行的函数改成setCodecForTr就可以了。
3. QTextCodec::setCodecForLocale(textc)
这个函数主要用于设置和对本地文件系统读写时候的默认编码格式。比如通过流读取一个文件时内容时的编码格式。或者通过qDebug()输出打印信息时的编码。
7 int main(int argc,char *argv[]){
8     QTextCodec *tc=QTextCodec::codecForName(”utf8″);
9     QTextCodec::setCodecForCStrings(tc);
10     QString str(”宁愿看见两个恶魔在拔河,也不愿看见一只天使在跳舞。”);
11
12     QTextCodec *tl=QTextCodec::codecForName(”utf8″);
13     QTextCodec::setCodecForLocale(tl);
14     qDebug()

Qt: Ansi、Unicode、UTF8字符串之间的转换和写入文本文件 
转自: http://www.blogjava.net/Yipak/articles/227015.html 
Ansi字符串我们最熟悉,英文占一个字节,汉字2个字节,以一个\0结尾,常用于txt文本文件
Unicode 字符串,每个字符(汉字、英文字母)都占2个字节,以2个连续的\0结尾,NT操作系统内核用的是这种字符串,常被定义为typedef unsigned short wchar_t;所以我们有时常会见到什么char*无法转换为unsigned short*之类的错误,其实就是unicode
UTF8是Unicode一种压缩形式,英文A在 unicode中表示为0x0041,老外觉得这种存储方式太浪费,因为浪费了50%的空间,于是就把英文压缩成1个字节,成了utf8编码,但是汉字在 utf8中占3个字节,显然用做中文不如ansi合算,这就是中国的网页用作ansi编码而老外的网页常用utf8的原因。
UTF8在还游戏里运用的很广泛,比如WOW的lua脚本等

下面来说一下转换,主要用代码来说明吧
写文件我用了CFile类,其实用FILE*之类的也是一样,写文件和字符串什么类别没有关系,硬件只关心数据和长度

Ansi转Unicode
介绍2种方法

  void   CConvertDlg::OnBnClickedButtonAnsiToUnicode()
  {
       //   ansi to unicode  
         char  *   szAnsi   =     "  abcd1234你我他  "  ;
       //  预转换,得到所需空间的大小  
         int   wcsLen   =   ::MultiByteToWideChar(CP_ACP, NULL, szAnsi, strlen(szAnsi), NULL,   0  );
       //  分配空间要给'\0'留个空间,MultiByteToWideChar不会给'\0'空间  
       wchar_t  *   wszString   =     new   wchar_t[wcsLen   +     1  ];
       //  转换  
       ::MultiByteToWideChar(CP_ACP, NULL, szAnsi, strlen(szAnsi), wszString, wcsLen);
       //  最后加上'\0'  
       wszString[wcsLen]   =     '  \0  '  ;
       //  unicode版的MessageBox API  
       ::MessageBoxW(GetSafeHwnd(), wszString, wszString, MB_OK);
 
       //  接下来写入文本
       //  写文本文件,头2个字节0xfeff,低位0xff写在前  
       CFile cFile;
     cFile.Open(_T(  "  1.txt  ")  , CFile::modeWrite   |   CFile::modeCreate);
       //  文件开头  
       cFile.SeekToBegin();
     cFile.Write(  "  \xff\xfe  "  ,   2  );
       //  写入内容  
       cFile.Write(wszString, wcsLen   *     sizeof  (wchar_t));
     cFile.Flush();
     cFile.Close();
     delete[] wszString;
     wszString   =  NULL;
 
 
       //  方法2
       //  设置当前地域信息,不设置的话,使用这种方法,中文不会正确显示
       //  需要#include  
       setlocale(LC_CTYPE,   "  chs  "  ); 
     wchar_t wcsStr[  100  ];
       //  注意下面是大写S,在unicode中,代表后面是ansi字符串
       //  swprintf是sprintf的unicode版本
       //  格式的前面要加大写L,代表是unicode  
       swprintf(wcsStr, L  "  %S  "  , szAnsi);
     ::MessageBoxW(GetSafeHwnd(), wcsStr, wcsStr, MB_OK);
 
 }

Unicode转Ansi
也是2种方法

 void  CConvertDlg::OnBnClickedButtonUnicodeToAnsi()
 {
      //  unicode to ansi 
     wchar_t *  wszString  =  L " abcd1234你我他 " ;
      // 预转换,得到所需空间的大小,这次用的函数和上面名字相反 
      int  ansiLen  =  ::WideCharToMultiByte(CP_ACP, NULL, wszString, wcslen(wszString), NULL,  0 , NULL, NULL);
      // 同上,分配空间要给'\0'留个空间 
      char *  szAnsi  =   new   char [ansiLen  +   1 ];
      // 转换
      // unicode版对应的strlen是wcslen 
     ::WideCharToMultiByte(CP_ACP, NULL, wszString, wcslen(wszString), szAnsi, ansiLen, NULL, NULL);
      // 最后加上'\0' 
     szAnsi[ansiLen]  =   ' \0 ' ;
      // Ansi版的MessageBox API 
     ::MessageBoxA(GetSafeHwnd(), szAnsi, szAnsi, MB_OK);
 
      // 接下来写入文本
      // 写文本文件,ANSI文件没有BOM 
     CFile cFile;
     cFile.Open(_T( " 1.txt ") , CFile::modeWrite  |  CFile::modeCreate);
      // 文件开头 
     cFile.SeekToBegin();
      // 写入内容 
     cFile.Write(szAnsi, ansiLen  *   sizeof ( char ));
     cFile.Flush();
     cFile.Close();
     delete[] szAnsi;
     szAnsi  = NULL;
 
 
      // 方法2
      // 和上面一样有另一种方法 
     setlocale(LC_CTYPE,  " chs " ); 
      char  szStr[ 100 ];
      // 注意下面是大写,在ansi中,代表后面是unicode字符串
      // sprintf 
     sprintf(szStr,  " %S " , wszString);
     ::MessageBoxA(GetSafeHwnd(), szStr, szStr, MB_OK);
 }

Unicode转UTF8

 void  CConvertDlg::OnBnClickedButtonUnicodeToU8()
 {
      //  unicode to UTF8 
     wchar_t *  wszString  =  L " abcd1234你我他 " ;
      // 预转换,得到所需空间的大小,这次用的函数和上面名字相反 
      int  u8Len  =  ::WideCharToMultiByte(CP_UTF8, NULL, wszString, wcslen(wszString), NULL,  0 , NULL, NULL);
      // 同上,分配空间要给'\0'留个空间
      // UTF8虽然是Unicode的压缩形式,但也是多字节字符串,所以可以以char的形式保存 
      char *  szU8  =   new   char [u8Len  +   1 ];
      // 转换
      // unicode版对应的strlen是wcslen 
     ::WideCharToMultiByte(CP_UTF8, NULL, wszString, wcslen(wszString), szU8, u8Len, NULL, NULL);
      // 最后加上'\0' 
     szU8[u8Len]  =   ' \0 ' ;
      // MessageBox不支持UTF8,所以只能写文件
 
      // 接下来写入文本
      // 写文本文件,UTF8的BOM是0xbfbbef 
     CFile cFile;
     cFile.Open(_T( " 1.txt " ), CFile::modeWrite  |  CFile::modeCreate);
      // 文件开头 
     cFile.SeekToBegin();
      // 写BOM,同样低位写在前 
     cFile.Write( " \xef\xbb\xbf " ,  3 );
      // 写入内容 
     cFile.Write(szU8, u8Len  *   sizeof ( char ));
     cFile.Flush();
     cFile.Close();
     delete[] szU8;
     szU8  = NULL;
 
 } 
UTF8转UNICODE

 void  CConvertDlg::OnBnClickedButtonU8ToUnicode()
 {
      // UTF8 to Unicode
      // 由于中文直接复制过来会成乱码,编译器有时会报错,故采用16进制形式 
      char *  szU8  =   " abcd1234\xe4\xbd\xa0\xe6\x88\x91\xe4\xbb\x96\x00 " ;
      // 预转换,得到所需空间的大小 
      int  wcsLen  =  ::MultiByteToWideChar(CP_UTF8, NULL, szU8, strlen(szU8), NULL,  0 );
      // 分配空间要给'\0'留个空间,MultiByteToWideChar不会给'\0'空间 
     wchar_t *  wszString  =   new  wchar_t[wcsLen  +   1 ];
      // 转换 
     ::MultiByteToWideChar(CP_UTF8, NULL, szU8, strlen(szU8), wszString, wcsLen);
      // 最后加上'\0' 
     wszString[wcsLen]  =   ' \0 ' ;
      // unicode版的MessageBox API 
     ::MessageBoxW(GetSafeHwnd(), wszString, wszString, MB_OK);
 
      // 写文本同ansi to unicode 
 } Ansi转换utf8和utf8转换Ansi就是上面2个的结合,把unicode作为中间量,进行2次转换即可