基于qt的嵌入式平台输入法:SYSZUXpinyin移植到arm后,UDP接收端中文乱码 本地中文乱码 解决...

SYSZUXpinyin输入法完全是用qt搭建的,移植到arm平台后,可以弹出软键盘,本人已成功。移植过程可以参考http://blog.chinaunix.net/uid-24219701-id-3077611.html这里,等有时间洒家写个移植的小细节。这里主要讲,移植后整个程序的文本、字符编码方式怎么调整才能避免乱码。

我的环境是在Fedora14下,默认的编码方式是UTF-8,在未移植SYSZUX拼音之前,main函数里设置:

QTextCodec::setCodecForTr(QTextCodec::codecForName("UTF-8")); //UTF-8
QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));


如此设置,UDP的接收端和发送端都可以正常显示中文。但SYSZUXpinyin采用的是GB2312方式,在主函数里必须设置QTextCodec::setCodecForTr(QTextCodec::codecForName("GB2312")); 在弹出的软键盘里才能正常显示中文。值得交代的是,main函数里只需要加这一句就可以了,多加任何如QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));或者QTextCodec::setCodecForCStrings(QTextCodec::codecForName("GB2312"))都会让软键盘显示异常!这块也是最纠结的地方.

主函数里设成GB2312后,除了按钮上的汉字可以正常显示外,其他的如标题等都不能正常显示了。因为我们的linux下qt默认的中文环境是UTF-8格式,要正常显示中文必须转化成UTF-8格式。解决方法是:在widget.h里,#include <QTextCodec>,然后定义:QTextCodec *tc; 在widget.cpp的构造函数里:tc = QTextCodec::codecForName("UTF-8"); 以后显示中文就用如:this->setWindowTitle(tc->toUnicode("Esto网络通讯模块----客户端"))来显示!

奇怪的是本地EditText是可以正常显示的,如ui->getTextEdit->insertPlainText( sendStr +"\n");操蛋就操蛋在发送端和接收端。在对端上中文都是乱码。我原以为tr设成GB2312后,对CStrings默认的也成了GB2312.既然发送端是GB2312,我曾实验发送端GB2312-----------接收端GB2312解析,显示出来还是乱码。将解析的GB2312再转成UTF-8还是乱码,郁闷我一个下午,几乎近于崩溃!后来我意识到,这个想当然cstrings的编码格式是错误的。

后来用QtCreator的帮助手册,问题出在udp的发送函数 在发送之前将QString转成QByteArray,


QString sendStr = ui->sendTextEdit->toPlainText();
QByteArray sendByteArray = sendStr.toAscii();

这里是通过.toAscii()方式转换的。转换时依据的编码方式就是setCodecForCStrings设的值,看下手册上咋说的:

QByteArray QString::toAscii () const
Returns an 8-bit representation of the string as a QByteArray.

If a codec has been set using QTextCodec::setCodecForCStrings(), it is used to convert Unicode to 8-bit char; otherwise this function does the same as toLatin1().

默认的是采用toLatin1()转换的,所以接受端无论按GB2312还是UTF-8怎么转都是乱码。而在主函数里又不能设定全局的setCodecForCStrings的编码方式。所以我最初尝试在send函数发送前,setCodecForCStrings()设成UTF-8,然后发送完后再将setCodecForCStrings()设成GB2312,发现只有第一次能发送中文,对端能正常显示。以后软键盘就乱码了。问题的根源在这里,SYSZUXpinyin的tr编码方式是GB2312,而setCodecForCStrings()这里应该是默认值,默认值多少呢?再看手册:

void QTextCodec::setCodecForCStrings ( QTextCodec * codec ) [static]
Sets the codec used by QString to convert to and from const char * and QByteArrays. If the codec is 0 (the default), QString assumes Latin-1.

默认的是Latin-1格式,也就是将codec设成0就恢复到默认状态了。用这个思路改,应该也能成功!

其实,问题的症结在toAscii()的时候依据的编码格式,能够在toAscii()之前,将QString转成UTF-8不就好了么。

将这句话QByteArray sendByteArray = sendStr.toAscii();改成QByteArray sendByteArray = sendStr.toUtf8().data();UDP的显示消息模块不变,依然用

QTextCodec *tutf=QTextCodec::codecForName("UTF-8");
QString dataStr =tutf->toUnicode(data);
还用UTF-8来解析,这样就能正常接收消息并显示中文了!


我后来又实验了上面的思路,在执行QByteArray sendByteArray = sendStr.toAscii(); 这句话之前,将setCodecForCStrings通过QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));设为UTF-8格式,在UDP发送函数的末尾加上,QTextCodec::setCodecForCStrings(0);将编码方式设为0,也就是默认的Latin-1.格式,经过测试,一切正常!两种方法都可以。接收函数保持不变。

我将udp部分的send函数和receive函数贴下,大家看完整的可以看我以前的帖子:

void Widget::send()
{
    autoScroll();
    QString sendStr = ui->sendTextEdit->toPlainText();
     QTextCodec::setCodecForCStrings(QTextCodec::codecForName("UTF-8"));
    QByteArray sendByteArray  = sendStr.toAscii();

   // QByteArray sendByteArray = sendStr.toUtf8().data(); //为了配合SYSZUXpinyin输入法,这种方法也可以
    QMessageBox box;
    if(sendStr.length()==0)
    {
        box.setText(tc->toUnicode("请输入发送内容"));
        box.exec();
    }
    else if(configFlag)
    {

        udpSocket1->writeDatagram(sendByteArray, sendByteArray.length(), *remoteHostAddr, 6665);

        //本地发送信息再信息交互窗口的显示
        QDateTime time;
        QString timeStr = time.currentDateTime().toString("yyyy-MM-dd hh:mm:ss ddd");
        ui->getTextEdit->setTextColor(QColor("red"));

        ui->getTextEdit->insertPlainText(tc->toUnicode("本机") + localIpStr + ": " + timeStr + "--UDP--\n");
        ui->getTextEdit->setTextColor(QColor("black"));
        ui->getTextEdit->insertPlainText( sendStr +"\n");
        ui->sendTextEdit->clear();          //点击发送后,发送编辑框内清零
        ui->sendTextEdit->setFocus();   //焦点停留在发送编辑框
        autoScroll();
    }
    else if(!configFlag)
    {
        box.setText(tc->toUnicode("请您先点击确认按钮!"));
        box.exec();
    }
      QTextCodec::setCodecForCStrings(0);//为了让移植的SYSZUXpin软键盘中文显示正常,必须让CStrings恢复到默认的Latin-1编码格式
}
void Widget::receive()
{
    while(udpSocket1->hasPendingDatagrams())
    {
        autoScroll();      
        QTextCodec *tutf=QTextCodec::codecForName("UTF-8");
        QDateTime time;
        QString timeStr = time.currentDateTime().toString("yyyy-MM-dd hh:mm:ss ddd");

        QByteArray data;
        data.resize(udpSocket1->pendingDatagramSize());
        udpSocket1->readDatagram(data.data(), data.size());
              //QString dataStr =  QString::fromUtf8(data.data());   //这样写也是正确的    
      
        QString dataStr =tutf->toUnicode(data);
        ui->getTextEdit->setTextColor(QColor("red"));
        ui->getTextEdit->insertPlainText(tc->toUnicode("远程")  + remoteIpStr+": "+ timeStr +"--UDP--\n" );
        ui->getTextEdit->setTextColor(QColor("black"));
        ui->getTextEdit->insertPlainText(dataStr  + "\n" );
        autoScroll();

    }

总结下:

1,SYSZUXpinyin官方只说是用GB2312编码,实际没有说全,他的tr要设成GB2312,而CStrings不用设,保留默认,其实是QString默认的Latin-1格式。而这个格式直接影响QString转QByteArray的编码格式,这个格式搞不对,在接收端就像没娘的熊瞎子,乱试就是显示不了正常的中文。


2,QString与QByteArray的转换


QString string;
QByteArray data;
data = string.toAscii(); //按照setCodecForCStrings()的格式进行转换

sendStr.toLatin1().data(); //如果转换格式未设置,则上面的转换等同于此,即按默认的Latin1格式转换
data = string.toUtf8().data(); //按UTF-8格式

QByteArray转QString:


QByteArray encodedString = "xxx";
QTextCodec *tc = QTextCodec::codecForName("UTF-8");
QString string = tc->toUnicode(encodedString);


3,其实现在我们再想想,如果UDP发送端对setCodecForCStrings不设UTF-8,

直接data = string.toAscii(); 让他按照默认的setCodecForCStrings()方式Latin-1进行转。

在接收方得到QByteArray之后,按照QTextCodec *tc = QTextCodec::codecForName("Latin1");

进行转换QString,得到Latin1编码格式的QString,再对QString的data数据进行UTF-8转换,

应该也能正常显示中文!


结论:

移植SYSZUXpinyin的注意了,为了让SUSZUXpinyin的软键盘正常拼出中文,

CStrings的编码格式一定要设成默认的Latin1格式,同时tr设成GB2312.

看来我们解决问题,一定要理清头绪,多看软件的英文参考文档,

从原理出发去解决,往往事半功倍!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值