qt中文編碼
來源:http://www.cublog.cn/u1/59481/showart_1947231.html
前些日子,被編碼折磨了一段時間,總結一下Qt中的編碼。
【Qt 編碼簡單實驗】
首先,Qt中得QString 類對字符串進行了封裝,其內部使用Unicode對傳入的串進行編碼。這樣一來,QString就可以處理絕大多數的國際語言。將QString中的字符根據語言翻譯的過程,也就是Qt 的Translater針對程序中使用含有的tr("XXXXX"),進行翻譯的過程。由於QString的Unicode編碼,和本地系統的編碼不一定是一致的(比如系統采用的GB2312的編碼)。這樣的話,就不能直接使用類似QString str("漢字")這樣的方法來存儲本地的漢字,是有問題的。
<系統是使用GB2312編碼的>
【試驗1】
QString str("漢字");
std::cout << "Straight Output:" << str << endl;
std::cout << "Local Output:" << str.local8Bit() << endl;
std::cout << "Unicode Output:" << str.unicode() << endl;
結果如下:
漢字 (正確)
@#$% (亂碼)
@#$% (亂碼)
【試驗2】
QString str = QString::fromLocal8Bit("漢字");
std::cout << "Straight Output:" << str << endl;
std::cout << "Local Output:" << str.local8Bit() << endl;
std::cout << "Unicode Output:" << str.unicode() << endl;
結果如下:
@#$% (亂碼)
漢字 (正確)
@#$% (亂碼)
首先說試驗1,因為str采用Unicode編碼,中文實際上沒有經過任何的編碼轉換直接存到str中,所以存入的Unicode已經是錯誤的(GB編碼的字符按照Unicode存的)。但是為什么第一個會正常顯示呢?因為標准輸入輸出是不進行任何的編碼解碼工作的,字符串由本地系統讀取時使用本地的字符集GB2312進行解碼,因為存入的字符串“漢字”正好是GB2312編碼的,正好得到了正確地結果!這有點負負得正的味道!QString只是充當了一個容器,里面存的是不正確的值。
對於試驗2來說,使用fromLocal8Bit()函數,實現了從本地字符集GB到Unicode的轉換,所以存在QString中的字符串是經過轉換的正確編碼。輸出的時候,要正確顯示,只能是再轉為本地的字符編碼,也就是使用local8Bit()轉換。由於存入QString的是正確的值,就可以進行包括國際化在內的許多工作!( 注意本地LANGUAGE環境變量!)
【Qt國際化的問題】
在文本顯示上,Qt 使用了Unicode 作為內部編碼,為了程序的國際化,通常我們在文本顯示的地方不直接輸入本地字符,用英文代替,比如要編寫一中文界面的 Qt 程序,應該在程序中使用英文,程序編寫完成后,把文本提取出來翻譯。對於需要翻譯的地方,首先是在該文本處用tr()函數標識,同時制作出.qm信息文件,並在程序中加入QTranslator即可。
比如我們在某一程序中有如下語句: setCaption(tr(“main window”)) 為了顯示中文,有兩種方法:
方法一:
1. 修改工程文件,加上TRANSLATIONS = xxx.ts
2. lupdate 工程文件名
3. 用linguist編輯剛生成的xxx.ts文件並保存
4. lrelease 工程文件名 xxx.qm
5. 在main.cpp中加入QFont font1(“unifont”,16,50,FALSE,QFont::Unicode);
6. qApp->setFont(font1);
7. QTranslator *translator = new QTranslator(0);
8. translator->load("xxx.qm",".");
9. qApp->installTranslator(translator);
方法二:
1. findtr 文件名(通常為CPP文件) > xxx.po
2. 編輯po文件,其中charset需由iso-8859-1改為GB2312,然后將“main window”翻譯成“主窗口”
3. msg2qm –scope zh_CN.GB2312 xxx.po xxx.qm
4. 在main.cpp中加入QFont font1(“unifont”,16,50,FALSE,QFont::Unicode);
5. qApp->setFont(font1);
6. QTranslator *translator = new QTranslator(0);
7. translator->load("xxx.qm",".");
8. qApp->installTranslator(translator);
方法三:
有時我們只是提供給本地用戶使用,無需國際化,QT提供這一支持,在QT中有許多本地字符集同unicode的轉換引擎,他們皆為QTextCodec的派生類,如QGbkCodec、QJisCodec, QHebrewCodec等。如:
QFont font1(“unifont”,16,50,FALSE,QFont::Unicode);
qApp->setFont(font1);
QString caption=“主窗口“;
QTextCodec *gk_codec=QTextCodec::codecForName(“GBK”);
setCaption(gk_codec->toUnicode(caption));
從上面可以看出,使用轉換引擎可以輕松實現中文顯示,簡要步驟如下:
1. 修改main.cpp文件,將字體改為unifont
QFont font1(“unifont”,16,50,FALSE,QFont::Unicode);
qApp->setFont(font1);
2. 在想漢化的內的頭文件中加入QTextCodec指針變量和轉換函數QString mytr(char *)
#include <qtextcodec.h>
QTextCodec* gbk;
QString mytr(const char *);
3. 在想漢化的類的實現文件中,修改類構造函數,加入:
gbk=QTextCodec::codecForName(“GBK”);
4. 在想漢化的類的實現文件中,添加mytr函數代碼
QString Form1::mytr(const char* chars) {
return gbk->toUnicode(chars,strlen(chars));
}
5. 在想漢化的類的實現文件中,用“mytr”替換“tr”
注:如果將codec成員變量改成QTextCodec派生類變量,編譯將通不過,比如將QTextCodec* gbk;改成QGbkCodec* gbk;編譯將報告此處有語法錯誤。
下面是相似的用法:
1. 修改***.cpp文件,在頂部加入codec頭文件
#include <qgbkcodec.h>
2. 在***.h文件中,加入mytr()函數聲明
QString mytr(char* buffer,int size);
3. 在***.cpp文件中,加入mytr()定義
QString mytr(char* buffer,int size) {
QGbkCodec* gbk=QTextCodec::codeForName(“GBK”);
return gbk->toUnicode(buffer,size);
}
4. 在需要顯示中文的地方,使用mytr函數即可
5. 修改main.cpp文件,將字體改為unifont
QFont font1(“unifont”,16,50,FALSE,QFont::Unicode);
qApp->setFont(font1);
備注1:在翻譯或轉換之前必須將Unicode字體調入,否則顯示不出中文,網上相關文章並未提及這一點,如果不顯式裝載該字體,系統默認的是Latin1,於是漢字顯不出來。
備注2:在編譯qt/embedded之前,必須修改qconfig-qpe.h配置文件的內容,將與TextCodec相關的宏定義給去掉,否則QTextCodec::codecForName(“GBK”)將返回NULL指針。
備注3:使用findtr命令時可同時查找多個文件的tr(),並將查找結果都放入一個文件內,源文件以空格隔開即可,另外,生成的.po和.qm文件的文件名最好與工程文件名相同!
備注4:如果要顯示繁體中文,則需要使用QTextCodec::codecForName(“big5”)。獲取本地的使用語言,用QTextCodec::locale(),它返回Qstring變量,通常如果是中文本地的話,通常其值為zh_CN.GB2312和zh_TW.Big5,根據這個返回字符串,可以加載相應的codec。如果程序只支持一種編碼,也可以直接把整個應用程序的編碼設置為一個默認的編碼標准,比如系統只需要顯示中文和英文,則可以直接設置應用程序的默認編碼標准是GBK,如下使用方法:
qApp->setDefaultCodec( QTextCodec::codecForName("GBK") );
QLabel *label = new QLabel( tr("中文標簽") );
備注5:如果使用本地的字符轉換器,可以使用Qstring的靜態函數Qstring::fromLocal8Bit(char* buffer,int size),將本地字符串轉換成UNICODE字符串,不過要設置好LANGUAGE環境變量。
【QTOpia中文化 】
1) findtr 文件名 > xxx.po
2) 編輯xxx.po文件
3) msg2qm –scope zh_CN.GB2312 xxx.po xxx.qm
4) 拷貝可執行文件到QPEDIR/bin目錄
5) 拷貝xxx.po和xxx.qm文件到QPEDIR/i18n/zh_CN目錄
6) 進入QPEDIR/apps/Applications目錄創建一新.desktop文件
7) iconv –f utf8 –t GB18030 xxx.desktop > xxx1.desktop
8) 編輯xxx1.desktop文件,主要是修改Exec、Icon、Name和Name[zh_CN]四項
9) iconv –f GB18030 –t utf8 xxx1.desktop > xxx.desktop
10) rm –f xxx1.desktop
11) qvfb –depth 16 &
12) cd $QPEDIR/bin
13) ./qpe
備注1:如果你的系統中有多個qtopia版本,要特別注意QTDIR、QPEDIR、LD_LIBRARY_PATH環境變量
備注2:可按照此方法漢化qtopia自帶的應用程序
備注3:po文件是中間文件,程序真正需要的是qm文件。iconv是系統自帶的內碼轉換工具,它能將utf8編碼的文件轉換成gb18030編碼的文件,反之也能,轉換這一步必不可少,因為desktop文件缺省是utf8編碼的,而我們的redhat linux 7。3中文操作系統用的卻是gb18030,所以在編輯器打開前需轉換。
Linux教程-Linux下應用程序開發:QT國際化編程
Qt 目前的版本(2.2.4)對國際化的支持已經相當完善。 在文本顯示上,Qt 使用了Unicode 作為內部編碼,可以同時支持多種編碼。 為 Qt 增加一種編碼的支持也比較方便,只要 增加該編碼和Unicode的轉換編碼便可以了。 Qt 目前支持ISO標准編碼ISO 8859-1, ISO 8859-2,ISO 8859-3,ISO 8859-4,ISO 8859-5,ISO 8859-7,ISO 8859-9,和 ISO 8859-15(對於阿拉伯語和希伯來語的支持正在開發之中),中文GBK/Big5,日文 eucJP/JIS/ShiftJIS,韓文eucKR,俄文KOI8-R。 當然也可以直接使用UTF8編碼。Qt 使用了自己定義的Locale機制,在編碼支持和信息文件(Message File)的翻譯上彌補了目前Unix上所普遍采用Locale和gettext的不足之處。 Qt 的這種機制可以使 Qt 的同一組件(QWidget)上同時顯示不同編碼的文本。 比如,Qt 的標簽上可以同時使用中文簡體 和中文繁體文本。
在文本輸入上,Qt 采用了XIM(X Input Method)標准協議,可以直接使用XIM輸入服務器。由於目前的絕大多數輸入服務器都是針對單一語言的,所以在 Qt 的標准輸入組件( QLineEdit,QMultiLineEdit)中的輸入受到單一編碼的限制,Qt 還不支持動態切換編碼 輸入的支持,這是它的不足之處。
1. Qt 的文本顯示
使用 Qt 編寫國際化的程序,最好不要在程序中直接使用特殊編碼的文本。 比如要 編寫一中文界面的 Qt 程序,應該在程序中使用英文,程序編寫完成后,把文本提取 出來翻譯。 這樣,程序還可以根據Locale的不同,支持多種語言。 下面介紹如何在 Qt 程序中標注字符串,如何提取並翻譯文本。
像普通的國際化過程一樣,Qt 使用了類似GNU gettext一樣的函數 QObject::tr(),它 用於從Qt的信息文件 .qm 中取出信息,這些信息是經過 Qt 的工具處理的。 Qt在處理 編碼時還使用了 QTranslator 類,可用於指定整個應用軟件的 的信息文件。
下面是一段使用了 QObject::tr()的代碼,它建立了一個彈出菜單,菜單項是"Quit", 它被放置在菜單條上,在菜單條上顯示的是標簽"File"。
QPopupMenu* popup;
popup = new QPopupMenu( this );
popup->insertItem( tr("&Quit"),qApp,SLOT(quit()) );
menubar->insertItem( tr("&File"),popup );
對於絕大多數情況,可以用上述方法處理。不過有時在定義某些變量中使用的字符 串,不能使用上述方法,但是為了讓Qt提取並翻譯該字符串,必須用某種方法標志出 來。Qt 定義了 QT_TR_NOOP() 和 QT_TRANSLATE_NOOP() 來標志它們。前者用於單個字符串,后者用於多個字符串。比如,
static const char* strings = {
QT_TR_NOOP( "Hello" ),
QT_TR_NOOP( "World" )
};
有時需要使用printf/sprintf之類的函數動態生成字符串,比如,
QStings s;
s.sprintf( "Button %d",i );
but->setText( s );
對這種使用方式的國際化是使用 arg() 函數。
QString s = tr( "Button %1" ).arg(i);
but->setText( s );
提取上述信息的方法是使用 Qt 提供的工具 findtr 命令:
findtr .cpp > i18n.po
它類似於GNU的 xgettext,上述文件的提取信息文件內包含,
....
"Content-Type: text/plain; charset=iso-8859-1\n"
#: i18n.cpp:34
msgid "ExampleWidget::&File"
msgstr ""
...
接下來是文本翻譯過程。 在Qt中翻譯信息文件時應該注意以下事項: (1) 提取的信息文件的編碼是iso-8859-1,在翻譯成某種語言(編碼)時應該 注意改動它的 字符集,比如對中文GB2312和Big5編碼,應該是, "Content-Type: text/plain; charset=gb2312\n"或者"Content-Type: text/plain; charset=big5\n"。 (2) 提取的信息有一個范圍,比如上面的文件指定的范圍是 ExampleWidget, 在翻譯 前應該把它去掉,變成 msgid "::&File"。(3) 被翻譯的字符串可能含有加速鍵符號,如 "&File"中的"F",如果翻譯成中文最好保留該信息,它可以翻譯成 "文件(&F)"。
對於翻譯后的文件(比如上面的翻譯文件存為 i18n_gb.po),必須使用 Qt 提供的 工具 msg2qm 把它轉換為 .qm 文件才能使用,
> msg2qm i18n_gb.po i18n_gb.qm
它類似於GNU的 msgfmt 命令。翻譯后的文件可以用Qt程序直接調用。
QTranslator *translator = new QTranslator(0);
translator->load("i18n_gb.qm",".");
qApp->installTranslator(translator);
此外,Qt 還提供了類似於 msgmerge 的工具 mergetr,它用於把新提取的信息 文件和已經翻譯過的信息文件融合起來,在此不再贅述。
在 Qt 中也可以直接使用 QTextCodec 來轉換字符串的編碼,這為在Qt下開發純 中文軟件帶來了便利條件,不過這種方法不符和國際化/本地化的習慣,
char *string = "中文和English混和字符串!"
QTextCodec* gbk_codec = QTextCodec::codecByName("GBK");
QString gbk_string = codec->toUnicode(string);
QLabel *label = new QLabel(gbk_string);
如果使程序只支持一種編碼,也可以直接把整個應用程序的編碼設置為GBK編碼, 然后在字符串之前 加tr(QObject::tr),
qApp->setDefaultCodec( QTextCodec::codecForName("GBK") );
QLabel *label = new QLabel( tr("中文標簽") );
如果使Qt根據Locale的環境變量取得字符集,可以使用
QString::fromLocal8Bit(str)。
本節的例子請參見 qt-i18n-example.tar.gz
2. Qt 的文本輸入
在輸入方面,Qt 的輸入條(QLineEdit)和編輯區(QMultiLineEdit)都支持 XIM,只要配合相應的輸入服務器,便可以輸入中文/日文/韓文。目前有許多支持XIM的軟件,比如 中文: Chinput/xcin/rfinput/q9,日文: kinput2/skkinput,韓文: ami/hanIM。
Qt程序的缺省輸入風格是OverTheSpot風格,它也支持 OffTheSpot風格和 Root風格。 用戶可以在起動程序時在命令行指定輸入風格,比如對程序app,
./app -inputstyle overthespot #缺省風格,光標跟隨
./app -inputstyle offthespot
./app -inputstyle root
經過 MiziLinux 補丁的Qt-2.2.0 支持 OnTheSpot 輸入風格,並且把它作為 缺省的輸 入風格。請參見 http://www.mizi.com/ko/kde/doc/onthespot/onthespot.html。
Qt 中的任何一個 Widget 都可以接受輸入,只要它可以有鍵盤聚焦(Keyboard Focus)。所以對特殊 Widget 的輸入處理只需要截獲鍵盤輸入,獲取從XIM服務器 來的字符串。 對於OverTheSport風格的支持,刷新XIM輸入服務器的位置即可。
3. Qt 的打印
在打印方面,XWindow下的 Qt 生成PostScript並使用lpr打印。 它含有QPrinter類, 可以方便地支持輸出頁面的控制。 對於中文打印,必須修正PostScript文件的輸出 部分。
http://blog.csdn.net/liuguangzhou123/article/details/7474102