【技术应用】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! |
另外的解决方案:
QTextCodec::codecForName(“GBK”)将返回NULL指针。
QTextCodec * BianMa = QTextCodec::codecForLocale(); //QTextCodec::codecForName ( "GBK" );
QT中文文件
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 条评论) 我要评论 | |
Qt: Ansi、Unicode、UTF8字符串之间的转换和写入文本文件
转自: http://www.blogjava.net/Yipak/articles/227015.html
Ansi字符串我们最熟悉,英文占一个字节,汉字2个字节,以一个/0结尾,常用于txt文本文件
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次转换即可
|