QT开发小结

目录

基础知识

1. Debug和Release区别

2. 信号与槽函数

3. 回调函数

开发有感

1. 善用内存

1.1 DB查询优化

1.2 海量数据(千万级以上)的优化

2. 善于解耦

2.1 高度可重复使用QML控件

2.2 QML中尽量少的调用业务内容(Q_INVOKABLE尽量少)

2.3 规范&简洁化coding

3. 多查询控件的查询控制

3.1 频繁的查询点击控制

3.2 并发控制


基础知识

1. Debug和Release区别

今天在自测过程中发现Debug和Release二者测试结果不同,

原因是Debug模式比Release模式运行略慢,在某些场景下,会造成测试结果不同。比如,存储文件时,写入结果可能会与程序运行速度有关,那么在这两种不同情况下就会结果不同。

2. 信号与槽函数

 MainCtrl mainCtr;
  mainCtr.registerAllContext(app, engine);
  const QUrl url(QStringLiteral("qrc:/qml/main.qml"));
  QObject::connect(
      &engine, &QQmlApplicationEngine::objectCreated, &app,
      [url, &mainCtr](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl) {
          QCoreApplication::exit(-1);
        } else {
          mainCtr.sigUiloadEnded();
        }
      },
      Qt::QueuedConnection);
  engine.load(url);
  return app.exec();

load(url)使得程序先展示主界面main.qml 给用户,避免等待,提升客户体验度。load完成后

QQmlApplicationEngine才会触发信号,从而使得mainCtr对象去加载一些必要的逻辑代码。
return app.exec();是为了将主界面阻塞住,不会一闪而过。

3. 回调函数

 auto func0 = [=](const QJsonObject &obj) { reportCheck(obj); };
 taskBase->setFunReportInfo(func0);

如上回调函数为 reportCheck(obj),setFunReportInfo(func0)将回调函数赋值给某个参数,func0为lambda表达式的写法。

mFunReportInfo,当某处使用该参数时便会调用回调函数reportCheck(obj)。如下code中通过 mFunReportInfo(val.toObject());将val值传给回调函数并执行reportCheck。
if ("funReport" == type) {
    if (mFunReportInfo) {
      mFunReportInfo(val.toObject());
    } else {
      qDebug() << "mFunReportInfo nullptr";
    }
  }

开发有感

1. 善用内存

最近在做数据查询的业务。对于要展示到qml中的部分数据(如通过时间段从库中查询的数据),也即是从数据库中取出的数据要存放到内存中去取用、展示等,而不是再另存入文件中从而增加IO次数,降低页面展示效率。

1.1 DB查询优化

在NoSQL中使用key:value的存储方式,查询时先查出所有key值(allKeyList),(而不是连key带value所有查出)然后根据需要再从allKeyList中拿key在DB中查询value,放入内存中进行取用,可大大减少内存的使用。

1.2 海量数据(千万级以上)的优化

基于上一条’DB查询优化’的思想,当需要的数据的海量级的时候 ,我们可以采取随用随查的方法减轻内存压力。如在一个带有分页功能的查询页面中,少量数据可以采用上一条方式查出所有需要的value后放入内存中使用,而海量数据的时候可以在点击某一页的时候再去从DB中查找相应Value,便可以大大减少内存的使用。

2. 善于解耦

2.1 高度可重复使用QML控件

qml控件使用时,各个属性、信号、业务功能处理要放置在使用控件的外层,而不是定义时的该文件中,以便于控件的后续维护和重复使用。

如在有多个搜索功能的场景中:

 该页面对应SelectTimePeriodItem.qml:

Item {
    property var curTabType: ""
    property bool enableInput: false
    signal clickLoadBtn(var obj)
    Row {
        spacing: 5
        SelectTime {
            id: idStartSelectTime
            width: 130
            height: keyHeight
        }
        Item {
            width: 10
            height: 30
            Text {
                width: parent.width
                height: parent.height
                text: "-"
                horizontalAlignment: Text.AlignHCenter
                verticalAlignment: Text.AlignVCenter
            }
        }
        SelectTime {
            id: idEndSelectTime
            width: 130
            height: keyHeight
        }
        RectButton {
            id: idImportBtn
            borderColor: "#d3d3d3"
            colorArray: ["orange", "transparent", "transparent"]
            width: 60
            height: 30
            borderWidth:1
            bText: gTrans.getTrans("load")
            onBtnClicked: {
                //业务处理
                clickLoadBtn({"st": idStartSelectTime.selectedTime, "et": idEndSelectTime.selectedTime})  
            }
        }
        RectButton {
            id: idOutputBtn
            colorArray: ["orange", "transparent", "transparent"]
            width: 60
            height: 30
            borderWidth:1
            borderColor: "#d3d3d3"
            bText: gTrans.getTrans("output")
            onBtnClicked: {
                //业务处理
                gDefectDataCtrl.outputCSVFile({"st": idStartSelectTime.selectedTime, "et": idEndSelectTime.selectedTime,"type":curTabType})  
            }
        }
        InputCtrlWithBtn {
            trans: gTrans.getTrans("enterQRcode")
            width: keyWidth + valueHeight
            height: keyHeight
            keyWidth: 110
            keyHeight: 30
            valueWidth: 200
            valueHeight: 30
            keyFontSize: 10
            valueFontSize: 10
            keyTxtColor: "black"
            borderColor: "black"
            valueTxtColor: "black"
            btnText: gTrans.getTrans("search")
            btnWidth: 60
            enabled: enableInput
            onSigBtnClicked: {
                //业务处理
                console.log("value", value)
                gDefectDataCtrl.getDataByQRcode(value) 
            }
        }
    }
    function enableInputTxt(curTabType) {
        return ("liXunDetectionRecord" === curTabType)
    }
}

以上SelectTimePeriodItem.qml中有三处需要处理的功能业务 ,且都在该控件本身编写这些业务,这样的方式造成后续再次使用SelectTimePeriodItem.qml控件时,就需要改写三处不同的业务功能。这种编码方式灵活性、可维护性较低,优化后如下:

Item {
    property var curTabType: ""
    property bool enableInput: false
    signal sigOp(var obj)
    Row {
        spacing: 5
        SelectTime {
            id: idStartSelectTime
            width: 130
            height: keyHeight
        }
        Item {
            width: 10
            height: 35
            Text {
                width: parent.width
                height: parent.height
                text: "-"
                horizontalAlignment: Text.AlignHCenter
                verticalAlignment: Text.AlignVCenter
            }
        }
        SelectTime {
            id: idEndSelectTime
            width: 130
            height: keyHeight
        }
        RectButton {
            id: idImportBtn
            borderColor: "#d3d3d3"
            colorArray: ["orange", "transparent", "transparent"]
            width: 60
            height: 35
            borderWidth: 1
            bText: gTrans.getTrans("load")
            onBtnClicked: {
                //交给信号统一处理
                sigOp({"type": "findByDateTime", "st": idStartSelectTime.selectedTime, "et": idEndSelectTime.selectedTime}) 
            }
        }
        RectButton {
            id: idOutputBtn
            colorArray: ["orange", "transparent", "transparent"]
            width: 60
            height: 35
            borderWidth:1
            borderColor: "#d3d3d3"
            bText: gTrans.getTrans("output")
            onBtnClicked: {
                //交给信号统一处理
                sigOp({"type": "outPutData"})
            }
        }
        InputCtrlWithBtn {
            trans: gTrans.getTrans("enterQRcode")
            width: keyWidth + valueHeight
            height: keyHeight
            keyWidth: 110
            keyHeight: 35
            valueWidth: 200
            valueHeight: 35
            keyFontSize: 10
            valueFontSize: 10
            keyTxtColor: "black"
            borderColor: "black"
            valueTxtColor: "black"
            btnText: gTrans.getTrans("search")
            btnWidth: 60
            enabled: enableInput
            onSigBtnClicked: {
                console.log("value", value)
                //交给信号统一处理
                sigOp({"type": "findByDmCode", "dmCode": value})
            }
        }
    }
    function enableInputTxt(curTabType) {
        return ("liXunDetectionRecord" === curTabType)
    }
}

使用 SelectTimePeriodItem:

SelectTimePeriodItem {
            id: idSelectTimePeriodItem
            curTabType: idTabDataTable.curType()
            enableInput: enableInputTxt(curTabType)
            //统一处理功能业务
            onSigOp: {
                var type = obj["type"]
                obj["tabName"] = curTabType
                if ("findByDateTime" === type || "findByDmCode" === type) {
                    console.log("for clearListMode")
                    idTabDataTable.clearListModel()
                    idTabDataTable.showPageIndicator(false)
                    idTabDataTable.setPageCnt(0)
                    if ("findByDmCode" === type) {
                        if ("" === obj["dmCode"]) {
                            tipTxt.textChanged(gTrans.getTrans("inputDmCodeNull"))
                            return;
                        }
                    }
                    gStatisticsTable.searchData(obj)
                } else if("outPutData" === type) {
                    gStatisticsTable.outPutCsv(curTabType)
                }
            }
        }

 优化后,控件SelectTimePeriodItem的封装性更高,code耦合度降低,易于使用和维护。

2.2 QML中尽量少的调用业务内容(Q_INVOKABLE尽量少)

如:当有多种类型的 搜索功能时(根据时间载入、输入二维码等)

可将QML中的多个Q_INVOKABLE函数合并到一个函数中进行统一处理

优化前:

//根据时间载入 
Q_INVOKABLE void getDataByTime(const QJsonObject &obj);
//根据二维码搜索
  Q_INVOKABLE void getDataByQRcode(const QString &QRcode);

优化后:

Q_INVOKABLE void searchData(const QJsonObject &obj);

void StatisticsTable::searchData(const QJsonObject &obj) {
  qDebug() << "searchData obj=" << obj;
  if (obj.contains("type")) {
    auto &&type = obj.value("type").toString();
    if ("findByDateTime" == type) {
      if (!mSearchingFlag) {
        findByDateTime(obj); //处理时间条件
      } else {
        qDebug() << "mSearchingFlag true do not searchData";
      }
    } else if ("findByDmCode" == type) {
      if (!mSearchingFlag) {
        findByDmcode(obj);//处理二维码条件
      } else {
        qDebug() << "mSearchingFlag true do not searchData";
      }
    }
  } else {
    qDebug() << "not contain type=" << obj;
  }
}

2.3 规范&简洁化coding

命名规范统一、易理解:函数名、属性名

同一个页面的多个功能保持function独立化,如下页面包括多种搜索及分页功能

搜素和分页的数据源相同,理论上可以并入同一个function中进行查询处理,但会造成功能耦合,code可阅读性降低。优化后将二者分离,各自处理控件查询功能:

  Q_INVOKABLE void searchData(const QJsonObject &obj);
  Q_INVOKABLE void switchPage(const QJsonObject &obj);

3. 多查询控件的查询控制

当涉及到多个查询业务(根据时间载入,根据二维码搜索),如下场景:

3.1 频繁的查询点击控制

以限制上一次查询操作未完成又开始下一轮查询操作,即用户点击‘载入’按钮后,随即多次点击输入二维码后的‘搜索’按钮。所以在每次查询操作时判通过断段flag 来决定是否执行该轮查询操作。如下:

void StatisticsTable::searchData(const QJsonObject &obj) {
  qDebug() << "searchData obj=" << obj;
  if (obj.contains("type")) {
    auto &&type = obj.value("type").toString();
    if ("findByDateTime" == type) {
      if (!mSearchingFlag) { //查询标志为false便可进入查询操作
        findByDateTime(obj);
      } else {
        qDebug() << "mSearchingFlag true do not searchData";
      }
    } else if ("findByDmCode" == type) {
      if (!mSearchingFlag) { //查询标志为false便可进入查询操作
        findByDmcode(obj);
      } else {
        qDebug() << "mSearchingFlag true do not searchData";
      }
    }
  } else {
    qDebug() << "not contain type=" << obj;
  }
}

或者在点击查询控件,查询结果未得到时将所有控件置为不可点击状态,让用户等待,使UI友好交互。 

3.2 并发控制

在上述查询功能中,每处查询都需要设置多线程的并发功能,在查询数据的同时放置ui加载卡顿,进行多线程调度,提高程序运行效率。

 QtConcurrent::run([=]() {
      mSearchingFlag = true;
      auto &&list = pDbCtrl->getDbInfo(obj, "liXunDmCode");
      mHashData.insert(tabName, list);
      if (0 == list.size()) {
        sigUpdate("noData", {});
      } else {
        QJsonObject objRes;
        objRes.insert("recordNum", list.size());
        objRes.insert("pageCnt", getPageCnt(list.size()));
        sigReport("searchDmCodeResult", objRes);
        sendDataAfterSearch(list);
      }
      mSearchingFlag = false;
    });

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值