初學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">
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
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中文文件
雖然C++標準中有了文件讀取的相關類,也很好用,但是在涉及到QT編程的時候卻用起來不方便了,因爲QT本身很多組件都是關聯的自身的QString類
型的字符串,所以再用C++本身String類型的時候就不是那麼方便了,需要進行轉化,這樣給程序帶來了複雜度,同時也帶來了轉化的開銷,所以如果用
QT開發,可以就用它本身所帶的這些類型進行處理,形成一個系統,便於數據在程序之中的交互和共用。
QT很好,但是在處理中文或者其他語言的時候要注意編碼格式,如果沒有注意,讀取文件的時候可能讀出來的就是亂碼或者乾脆程序就死掉了,這是我們所不願意看到的,下面就講講怎麼樣通過QT的類來讀取中文文件。
介紹部分
我們需要用到幾個頭文件中的類:
#include <qstring.h>
#include <qfile.h>
#include <qtextstream.h>
#include <qtextcodec.h>
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 <qstring.h>
#include <qfile.h>
#include <qtextstream.h>
#include <qtextcodec.h>
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.h>
QTextCodec::setCodecForTr(QTextCodec::codecForName("GB2312")) ;
談談Qt的中文編碼~ | |
|
|
來源: ChinaUnix博客 日期: 2009.07.04 11:23 (共有1 條評論) 我要評論 | |
轉自: 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<locale.h> 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次轉換即可
|