QT下对硬件固件协议的测试小结及几个QT遇到的问题解决

阅读更多

为基于网络udp通信的固件协议进行测试,用QT编写测试工具。其间遇到了一些问题,并逐个解决。特记录在此。

1. 因为基于网络协议,所以需要获取IP,方便发送并接收UDP数据。但因虚拟网卡等,所以需要筛选IP。

 

    QHostAddress addr;
    QList list = QNetworkInterface::allAddresses();
    foreach (addr, list)
    {
       if(addr.protocol() == QAbstractSocket::IPv4Protocol){
           if (addr.toString().contains("192.168")){
               address = QHostAddress(addr.toString());
           }
       }
    }

而在发送命令时,若是以广播方式发送,则也需要考虑使用哪块网卡进行广播。因此要先绑定ip。

udpCMDSocket = new QUdpSocket(this);
udpCMDSocket->bind(QHostAddress(ip));
udpCMDSocket->writeDatagram(cmd.toLocal8Bit(), HubAddr, port);

 

2. 当在主UI上临时需要做高占用的任务如while循环时,可以用QApplication::processEvents()来响应界面上的待处理事件。

 

while (!binFile.atEnd() {
                QByteArray byte = binFile.read(len);
                。。。
                sendCMD2Port(cmd, HubAddr, port);
                Sleep(interval);
                QApplication::processEvents();
            }

 3. 打开文件,若已有路径显示已有路径

    QString tmpBinfile;
    if (BinFilePath.size() == 0)
        tmpBinfile = QFileDialog::getOpenFileName(this, tr("Open Bin File"), ".", tr("Bin File(*.bin)"));
    else
        tmpBinfile = QFileDialog::getOpenFileName(this, tr("Open Bin File"), BinFilePath, tr("Bin File(*.bin)"));

 4. 读取文件,生成QListWidget,并排序

bool CaseInsSort(const QString &info1, const QString &info2)
{
    return info1.toLower() < info2.toLower();
}

void loadCases()
{
    QFile file(filename);
    if (file.open(QFile::ReadWrite|QIODevice::Text)){
        QTextStream data(&file);
        QStringList fonts;
        QString line1;
        QString line2;
        while (!data.atEnd()){
            line1 = data.readLine();
            line2 = data.readLine();
            fonts<addItems(fonts);//把各行添加到listwidget
        file.close();
    }
}

 5. QListWidgetItem改名

void renameCase()
{
    QListWidgetItem *caseItem = caseList->currentItem();
    if (caseItem){
        caseList->openPersistentEditor(caseItem);
    }
}

 6. 发送UDP命令

void sendCMD2Port(QString cmd, QHostAddress HubAddr, int port)
{
    udpCMDSocket = new QUdpSocket(this);
    udpCMDSocket->writeDatagram(cmd.toLocal8Bit(), HubAddr, port);
    udpCMDSocket->close();
}

 7. 监听线程独立于主线程,包括对监听数据处理都在run中

void listenPortThread::run()
{
    QUdpSocket udpListenSocket;
    bool result = udpListenSocket.bind(address, port,QUdpSocket::ShareAddress);//绑定到指定的端口号
    if(!result)//若绑定不成功,给出出错信息
    {
        udpListenSocket.close();
        stop();
        return;
    }
    islisten = true;
    m_bStop = false;
    while(!m_bStop)
    {
        QByteArray array;
        QHostAddress address;
        quint16 port;
        if (islisten){
            while (udpListenSocket.hasPendingDatagrams()) {
                array.resize(udpListenSocket.pendingDatagramSize());//根据可读数据来设置空间大小
                udpListenSocket.readDatagram(array.data(),array.size(),&address,&port); //读取数据
                QString str = array;
                。。。

 8.单次定时器控制,判断是否在时限内收到回复。到时间在timeout函数中判断。

       QTimer::singleShot(1500,this,SLOT(timeout()));
        sendCMD2Port(cmd, HubAddr, port);

 9. 解析收到的json回复,通过关键字查询结果

bool listenPortThread::parseJson(QByteArray array, QString *sendID, QString *result, QString key){
    QJsonParseError jsonError;
    QJsonDocument doucment = QJsonDocument::fromJson(array, &jsonError);  // 转化为 JSON 文档
    if (!doucment.isNull() && (jsonError.error == QJsonParseError::NoError)) {  // 解析未发生错误
        if (doucment.isObject()) { // JSON 文档为对象
            QJsonObject object = doucment.object();  // 转化为对象
            if (!key.isEmpty() && object.contains(key)){
                QJsonValue Jvalue = object.value(key);
                if (Jvalue.isString()) { 
                    QString strvalue = Jvalue.toString();
                    *result = strvalue;
                }
            }

 10. 返回的json数据,包括base64数据时,解码并还原为float

QJsonValue Jdata = object1.value("data");
if (Jdata.isString()) {  
    QString strdata = Jdata.toString();
    QByteArray Hex = QByteArray::fromBase64(strdata.toLatin1()).toHex();
    QString calidata = "";
    for (int i=0; i<12; i++){
        QString str =Hex.mid(i*8+6,2)+Hex.mid(i*8+4,2)+Hex.mid(i*8+2,2)+Hex.mid(i*8,2); //低位到高位
        int iHex = str.toUInt(0,16);
        float fHex = *(float*)&iHex ;
        calidata += QString("%1, ").arg(fHex);
    }
    *result = calidata;
}

11. 在pro文件中通过VERSION设定APP版本号,并在程序中获取APP版本号

写道
In the YourApp.pro:

VERSION = 0.0.0.1
DEFINES += APP_VERSION=\\\"$$VERSION\\\"

In the main.cpp:

#include
QCoreApplication::setApplicationVersion(QString(APP_VERSION));

Wherever else in your sources, e.g. in the imaginary controller.cpp:

#include
QString yourAppVersion = QCoreApplication::applicationVersion();

 

12. 发布release版本程序,自动打包QT所需动态库

写道
Qt官方开发环境默认使用动态链接库方式,在发布生成的可执行程序时,我们需要复制一大堆动态库,如果自己去复制动态库,很可能丢三落四,导致程序在别的电脑里无法正常运行。 因此 Qt 官方开发环境里自带了一个部署工具来帮助开发者自动拷贝大部分的依赖库。

Windows开发环境下windeployqt工具 (如果你已经将Qt的bin目录加入PATH环境,那么你可以直接在命令行使用windeployqt调用.)。首先,将项目中的release文件中的可执行文件拷到一个新建的文件夹中,例如project.exe,用Qt自带的生成必备的dll文件的程序windeployqt,来把必要的动态库拷到该文件夹中,打开命令行,输入windeployqtproject.exe,这时候大部分的dll文件都自动拷贝过来了,但是如果项目还用了一些其他的SDK,比如OpenCV,Chartdir51等等,就需要手动将所需dll拷贝过来,如果不知道还需要哪些软件,可以用Dependency Walker来查看缺少哪些dll文件。

注意:如果发布的应用是Qt Quick Application应用,那么命令行需要加上QML的安装目录。命令中的D:\Qt\Qt5.5.1\qml是qml的安装目录,请换成你自己的qml安装目录!!!!!

windeployqt hello.exe --qmldir D:\Qt\Qt5.5.1\qml

接下来要高大上的朋友就可以用Enigma VirtualBox软件虚拟化工具将多个文件封装到应用程序主文件,从而制作成为单执行文件的绿色软件。

 
13. 制作多语言版,使用QT linguist做语言包
写道
1. 在pro文件中添加TRANSLATIONS += filename_CN.ts
2. 工具-->外部-->linguist-->更新,来生成ts文件。但若直接使用,则qt可能会报错。因为没有找到VS的环境。所以

a. Create a translate.bat with the following single-line content:

"%programfiles(x86)%\Microsoft Visual Studio\2017\Community\VC\Auxiliary\Build\vcvars64.bat" & lupdate.exe %1

and put it under %{CurrentProject:QT_INSTALL_BINS} (in my case C:\Qt\Qt5.9.1\5.9.1\msvc2017_64\bin). Make sure that the translate.bat contains the correct path to vcvars64.bat on your machine. You may as well put another version of vcvars if you need.

b. In Qt Creator select Tools/Options/Environment/External Tools and then Add Tool under Linguist category. Name it something like Create/Update TS files. Setup the fields for this entry as follows:

Executable: %{CurrentProject:QT_INSTALL_BINS}\translate.bat,

Arguments: %{CurrentProject:FilePath},

Working directory: %{CurrentProject:QT_INSTALL_BINS},

as shown here: External Tools, then apply the changes and close the Options window.

c. Go to Tools/External/Linguist, select Create/Update TS files and now it should do the job as usual.

3. 在linguist中编辑ts文件,加语言翻译
4. 在linguist直接发布,或用qt的工具-->外部-->linguist-->发布,来用ts文件生成qm文件
5. 在主程序中
     QApplication app(argc, argv);
     QTranslator translator;
     bool ok=translator.load(":/qm/filename_CN.qm");
     app.installTranslator(&translator);

 

14. qt全局宏变量

写道
pro中添加如下宏定义代码:

     DEFINES += HELLO=\\\"$$PWD/\\\"
     DEFINES += SUCCESS=\\\"string\\\"

在.cpp中测试代码如下:

     #ifdef HELLO
     qDebug()<<"HELLO="<     #else
     qDebug()<<"bye";
     #endif

 

你可能感兴趣的:(qt,json)