Какие функции переопределить с помощью пользовательского QSortFilterProxyModel - PullRequest
1 голос
/ 13 марта 2019

Итак, у меня есть собственный QAbstractItemModel, который переопределяет следующие функции:

QVariant data(..) const;
QVariant headerData(..) const;
QModelIndex index(..) const;
QModelIndex parent(..) const;
int rowCount(..) const;
int columnCount(..) const;
virtual bool removeRows(..);

Нужно ли переопределять все это в пользовательском QSortFilterProxyModel, который использует мою модель в качестве источника?

Источником моей путаницы является этот отрывок из руководства:

Поскольку QAbstractProxyModel и его подклассы являются производными от QAbstractItemModel, большая часть того же совета относительно подклассов обычных моделей также применима к проксимоделей.Кроме того, стоит отметить, что многие реализации функций по умолчанию в этом классе написаны так, чтобы они вызывали эквивалентные функции в соответствующей исходной модели.Этот простой механизм прокси может потребоваться переопределить для исходных моделей с более сложным поведением;например, если исходная модель предоставляет пользовательскую реализацию hasChildren (), вы также должны указать ее в прокси-модели.https://doc.qt.io/archives/qt-4.8/qsortfilterproxymodel.html#subclassing

1 Ответ

1 голос
/ 13 марта 2019

Нет, вам не нужно переопределять эти функции.

Простой пример использования QSortFilterProxyModel ниже:

Model.hpp

#pragma once

#include <QAbstractListModel>

class Model : public QAbstractListModel {
    Q_OBJECT
public:
    enum Roles {
        Name = Qt::UserRole + 1
    };

    Model(QObject* parent = nullptr);
    virtual ~Model();

    // QAbstractItemModel interface
    int rowCount(const QModelIndex &parent) const noexcept override;
    QVariant data(const QModelIndex &index, int role) const noexcept override;
    QHash<int, QByteArray> roleNames() const noexcept override;

private:
    QStringList list_;

};

model.cpp

#include "Model.hpp"

Model::Model(QObject *parent) : QAbstractListModel{parent}
{
    list_ << "Adam" << "John" << "Alice" << "Kate";
}

Model::~Model()
{

}

int Model::rowCount(const QModelIndex &parent) const noexcept
{
    return list_.size();
}

QVariant Model::data(const QModelIndex &index, int role) const noexcept
{
    if(!index.isValid() || role < Name)
        return QVariant{};

    auto name = list_[index.row()];

    if(role == Name)
        return name;

    return QVariant{};
}

QHash<int, QByteArray> Model::roleNames() const noexcept
{
    return QHash<int, QByteArray>{{Name, "name"}};
}

FilterModel.hpp

#pragma once

#include <QSortFilterProxyModel>

class FilterModel : public QSortFilterProxyModel {
    Q_OBJECT
public:
    FilterModel(QObject* parent = nullptr);
    virtual ~FilterModel();

    Q_INVOKABLE void setFilterString(const QString& filter) noexcept;

};

FilterModel.cpp

#include "FilterModel.hpp"
#include "Model.hpp"

FilterModel::FilterModel(QObject *parent) : QSortFilterProxyModel{parent}
{

}

FilterModel::~FilterModel()
{

}

void FilterModel::setFilterString(const QString &filter) noexcept
{
    setFilterCaseSensitivity(Qt::CaseInsensitive);
    setFilterFixedString(filter);
}

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>

#include "Model.hpp"
#include "FilterModel.hpp"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);

    Model model;
    FilterModel filterModel;

    filterModel.setSourceModel(&model);
    filterModel.setFilterRole(Model::Name);

    QQmlApplicationEngine engine;

    QQmlContext* ctx = engine.rootContext();
    ctx->setContextProperty("filterModel", &filterModel);

    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
    if (engine.rootObjects().isEmpty())
        return -1;

    return app.exec();
}

main.qml

import QtQuick 2.11
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3

ApplicationWindow {
    visible: true

    width: 200
    height: 300

    ColumnLayout {
        anchors.fill: parent

        TextField {
            id: textField

            Layout.fillWidth: true

            placeholderText: "Search..."

            onTextChanged: { filterModel.setFilterString(textField.text) }
        }

        ListView {
            id: view

            Layout.fillHeight: true
            Layout.fillWidth: true

            clip: true

            model: filterModel

            delegate: Text {
                width: parent.width

                text: name

                font.pointSize: 14
                font.bold: true

                verticalAlignment: Text.AlignVCenter
                horizontalAlignment: Text.AlignHCenter
            }
        }
    }
}

Обратите внимание, если у вас есть пользовательский класс в качестве элемента модели, вы должны переопределить

 bool QSortFilterProxyModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const

для вашего фильтра.

...