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,所以在編輯器打開前需轉換。
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 輸入風格,並且把它作為 缺省的輸 入風格。請參見 https://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文件的輸出 部分。
最後更新:2017-04-02 06:51:28