• QML使用C++model(排序/搜索)


    上一篇介绍介绍了C++model的基本用法,只实现了增删改,实际项目开发中,还有很常见的功能就是排序和查询。Qt提供了QSortFilterProxyModel实现排序和查询的功能。

    排序查询

    QSortFilterProxyModel,顾名思义,排序过滤代理model,搜索查询本质上就是过滤。至于代理,就是QSortFilterProxyModel只是原model的代理,原始数据还是在原model上,代理model根据相应的规则存储进行处理后的数据,源数据在源model是不变的。比如芒果的代理商,实际上果农果园里有很多品种的芒果,但市场上主流的两三种,代理商售卖就只卖这两三种,果农就是原model,代理商就是QSortFilterProxyModel。

    QSortFilterProxyModel提供了以下接口绑定model

    void setSourceModel(QAbstractItemModel *sourceModel) override

    排序

    sort接口实现排序,第二个参数是选择升序还是降序

    void sort(int column, Qt::SortOrder order = Qt::AscendingOrder) override

    对于我们自定义的model来说,需要选择要排序的role类型,一般搭配setSortRole使用

    void setSortRole(int role);

    对于自定义的类型,需要自定义自己的排序规则,可重载

    bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
    1. bool MySortFilterProxyModel::lessThan(const QModelIndex &left,
    2. const QModelIndex &right) const
    3. {
    4. QVariant leftData = sourceModel()->data(left);
    5. QVariant rightData = sourceModel()->data(right);
    6. //! [4]
    7. //! [6]
    8. if (leftData.userType() == QMetaType::QDateTime) {
    9. return leftData.toDateTime() < rightData.toDateTime();
    10. } else {
    11. static const QRegularExpression emailPattern("[\\w\\.]*@[\\w\\.]*");
    12. QString leftString = leftData.toString();
    13. if (left.column() == 1) {
    14. const QRegularExpressionMatch match = emailPattern.match(leftString);
    15. if (match.hasMatch())
    16. leftString = match.captured(0);
    17. }
    18. QString rightString = rightData.toString();
    19. if (right.column() == 1) {
    20. const QRegularExpressionMatch match = emailPattern.match(rightString);
    21. if (match.hasMatch())
    22. rightString = match.captured(0);
    23. }
    24. return QString::localeAwareCompare(leftString, rightString) < 0;
    25. }
    26. }

    上面的例子中只比较邮箱部分的数据

    过滤

     过滤最常见的的应用就是搜索功能,就是过滤匹配关键字,使用QSortFilterProxyModel也很容易实现

    重写函数

    bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
    1. bool DataListProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
    2. {
    3. QModelIndex index0 = sourceModel()->index(sourceRow, 0, sourceParent);
    4. auto typeData = sourceModel()->data(index0, DataListModel::TypeRole).toString();
    5. auto sizeData = sourceModel()->data(index0, DataListModel::SizeRole1).toString();
    6. return typeData.contains(filterRegExp()) || sizeData.contains(filterRegExp());
    7. }

    里面实现想要过滤的内容,上面的例子就返回满足TypeRole和SizeRole1其中一项的数据

    执行过滤是调用,参数就是过滤规则

    void setFilterRegExp(const QRegExp &regExp);

    QRegExp除了关键的key值pattern外,还有Qt::CaseSensitivity支持是否区分大小写,第三个参数是其他一些匹配规则,我也很少用到

    1. explicit QRegExp(const QString &pattern, Qt::CaseSensitivity cs = Qt::CaseSensitive,
    2. PatternSyntax syntax = RegExp);

    demo展示

     以上就是基于QSortFilterProxyModel实现的排序和搜索功能,实现还是很简单的

    源model和上一篇博客介绍的model是一样的,在此基础上增加一个QSortFilterProxyModel,不同的是QML显示的是QSortFilterProxyModel,就是QML显示的是处理的数据,这个应该好理解。

    1. #include <QSortFilterProxyModel>
    2. class DataListProxyModel : public QSortFilterProxyModel
    3. {
    4. Q_OBJECT
    5. public:
    6. explicit DataListProxyModel(QObject *parent = nullptr);
    7. Q_INVOKABLE void setFilter(const QString &text);
    8. Q_INVOKABLE void startSort();
    9. protected:
    10. bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override;
    11. // bool lessThan(const QModelIndex &source_left, const QModelIndex &source_right) const override;
    12. };
    1. #include "datalistproxymodel.h"
    2. #include "datalistmodel.h"
    3. DataListProxyModel::DataListProxyModel(QObject *parent):
    4. QSortFilterProxyModel(parent)
    5. {
    6. }
    7. void DataListProxyModel::setFilter(const QString &text)
    8. {
    9. QRegExp regExp(text);
    10. this->setFilterRegExp(regExp);
    11. }
    12. void DataListProxyModel::startSort()
    13. {
    14. setSortRole(DataListModel::TypeRole);
    15. sort(0, Qt::DescendingOrder);
    16. }
    17. bool DataListProxyModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const
    18. {
    19. QModelIndex index0 = sourceModel()->index(sourceRow, 0, sourceParent);
    20. auto typeData = sourceModel()->data(index0, DataListModel::TypeRole).toString();
    21. auto sizeData = sourceModel()->data(index0, DataListModel::SizeRole1).toString();
    22. return typeData.contains(filterRegExp()) || sizeData.contains(filterRegExp());
    23. }

    主函数main

    1. int main(int argc, char *argv[])
    2. {
    3. #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    4. QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
    5. #endif
    6. QGuiApplication app(argc, argv);
    7. DataListModel model;
    8. model.append( ModelData("wolf.jpg", "Medium") );
    9. model.append( ModelData("polarbear.jpg", "Large") );
    10. model.append( ModelData("quoll.jpg", "Small") );
    11. DataListProxyModel proxyModel;
    12. proxyModel.setSourceModel(&model);
    13. QQmlApplicationEngine engine;
    14. engine.rootContext()->setContextProperty("myModel", &proxyModel);
    15. const QUrl url(QStringLiteral("qrc:/main.qml"));
    16. QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
    17. &app, [url](QObject *obj, const QUrl &objUrl) {
    18. if (!obj && url == objUrl)
    19. QCoreApplication::exit(-1);
    20. }, Qt::QueuedConnection);
    21. engine.load(url);
    22. return app.exec();
    23. }

    设置setSourceModel,该例子采用C++与QML交互的另一种方式,model是在c++创建,把对象注册到QML中使用,该例子是注册对象QSortFilterProxyModel,使用代理model进行显示

    1. import QtQuick 2.15
    2. import QtQuick.Window 2.15
    3. import QtQuick.Controls 2.15
    4. Window {
    5. width: 640
    6. height: 480
    7. visible: true
    8. title: qsTr("Hello World")
    9. Column {
    10. anchors.fill: parent
    11. Row {
    12. TextField {
    13. id: searchInput
    14. width: 100
    15. height: 30
    16. onTextChanged: {
    17. myModel.setFilter(text)
    18. }
    19. }
    20. Button {
    21. text: "sort"
    22. onClicked: {
    23. myModel.startSort()
    24. }
    25. }
    26. }
    27. ListView {
    28. id: listview
    29. clip: true
    30. width: parent.width
    31. height: parent.height
    32. model: myModel
    33. delegate: Item {
    34. id: delegate
    35. width: listview.width
    36. height: 30
    37. Row {
    38. spacing: 5
    39. Text {
    40. text: type
    41. }
    42. Text {
    43. text: size
    44. color: "red"
    45. }
    46. Button {
    47. height: parent.height
    48. onClicked: {
    49. myModel.remove(index);
    50. }
    51. }
    52. }
    53. }
    54. }
    55. }

    结语

    以上就是一个排序搜索的功能,界面布局有点挫,将就着看,重点是功能。更多例子了解可参考Qt例子

    前两个例子是Widget的实现的, 但QSortFilterProxyModel的用法是一样的,第三个是QML,但使用的是QML,没有基于QSortFilterProxyModel,有需要可以看看。由于边幅的原因,基于model的撤销恢复功能留到下一篇来介绍了。

  • 相关阅读:
    一套.Net6可落地的微服务、分布式开源项目
    响应数据web
    香港金融科技周VERTU CSO Sophie谈Web3.0的下一个风口 手机虚拟货币移动支付
    HTTPS安全通信和SSL Pinning
    日常电脑出现msvcp140.dll丢失的解决办法
    一个悄然崛起的国产软件
    5、MySql 全局锁、表锁、行锁
    Leetcode209. 长度最小的子数组
    04、SpringAOP详解
    利用arcgis模拟制作水下地形
  • 原文地址:https://blog.csdn.net/a137748099/article/details/125435835