Qt开发者来说,特别是初学者,往往最头疼的是编码的问题。举个例子。
1、控件上设置中文标签,发现显示出来是乱码?怎么解决。如果标签是常量字符串(含中文),怎么处理。如果标签是变量,且可能包含字符串,又咋处理?
2、Qt应用与其他应用存在进程间交互,数据中不可避免的包含中文字符。Qt应用譬如使用的是utf8编码,其他应用可能是使用unicode编码或者其他编码,数据交互过程中的中文乱码问题怎么处理?
…
先只抛出这两个问题。看看有没有戳中朋友们的肋骨。
然后我们说说这两个问题怎么在实际的项目开发过程中避免和解决。
问题一解决方案:
1、控件上显示中文标签乱码问题。
常量字符标签(含中文)的显示方式
(1)【方案一】使用Qt国际化,代码中全部用英文,然后加ts翻译成中文。这种方法不是不可以,但是很stupid,为了解决小小乱码的问题,还要引入翻译模块,简直就是高射炮打蚊子,好么。当然,如果应用本身有国际化需求,对应发布国际市场,那你这么干也无可厚非。
(2)【方案二】 采用如下方式声明和定义常量字符串标签名:
QStringLiteral("这是常量字符串");
如果只是按照上面的方式去设置,譬如:
label->setText(QStringLiteral("这是常量字符串"));
你发现输出展示的仍是乱码岂不是要跟我扯皮。还有两个关键的步骤,你要注意:
1、通常,我们默认编码设置成UTF-8 的模式【重要!重要!】
2、当前页,在代码编辑区右键鼠标,选择最下面的 ”add Utf-8 bom” 【这里非常重要,估计很多几年开发经验的Qt从业者也未必会注意到】
另外,一个好的项目一定要注意编码的统一,别一会儿搞个utf8,一回儿搞个gbk或者其他的编码,弄来弄去,项目越来越烂,到最后维护成本越来越高,开发者也被搞的头疼。
问题二解决方案:
1、其实解决这个问题并不只是需要编码层面,更加要注意的是项目管理层面(代码管理),我们在设计之初,就要严格要求编码的一致性。
譬如,Qt应用(作为主应用)与其他不同编码的应用进程间数据交互,我们规定好,Qt应用方接收数据和输出数据必须为utf8编码,定义数据传交互数据类型为char字符串(单字节,宽字节也必须转单字节后再交互)。
附一个转换方法:
std::string stringToUTF8(const std::string& str)
{
int nwLen = ::MultiByteToWideChar(CP_ACP, 0, str.c_str(), -1, NULL, 0);
wchar_t* pwBuf = new wchar_t[nwLen + 1];
ZeroMemory(pwBuf, nwLen * 2 + 2);
::MultiByteToWideChar(CP_ACP, 0, str.c_str(), str.length(), pwBuf, nwLen);
int nLen = ::WideCharToMultiByte(CP_UTF8, 0, pwBuf, -1, NULL, NULL, NULL, NULL);
char* pBuf = new char[nLen + 1];
ZeroMemory(pBuf, nLen + 1);
::WideCharToMultiByte(CP_UTF8, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);
std::string strRet(pBuf);
delete []pwBuf;
delete []pBuf;
pwBuf = NULL;
pBuf = NULL;
return strRet;
}
std::string UTF8ToString(const std::string& str)
{
int nwLen = MultiByteToWideChar(CP_UTF8, 0, str.c_str(), -1, NULL, 0);
wchar_t* pwBuf = new wchar_t[nwLen + 1];
memset(pwBuf, 0, nwLen * 2 + 2);
MultiByteToWideChar(CP_UTF8, 0, str.c_str(), str.length(), pwBuf, nwLen);
int nLen = WideCharToMultiByte(CP_ACP, 0, pwBuf, -1, NULL, NULL, NULL, NULL);
char* pBuf = new char[nLen + 1];
memset(pBuf, 0, nLen + 1);
WideCharToMultiByte(CP_ACP, 0, pwBuf, nwLen, pBuf, nLen, NULL, NULL);
std::string strRet = pBuf;
delete []pBuf;
delete []pwBuf;
pBuf = NULL;
pwBuf = NULL;
return strRet;
}
其他应用根据此协议来自主转换对应编码即可(当然,这里有个条件,Qt应用必须为主应用,否则一个子应用没有必要这么强势)。
这一步在项目设计之初就规划好,后续会避免编码的坑。尤其是多应用交互的场景。