Created
October 11, 2020 17:48
-
-
Save mitchcurtis/f57f945e014ef1065e73a5fcefff7d1d to your computer and use it in GitHub Desktop.
ProxyModelNoneEntry with QSortFilterProxyModel
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <QGuiApplication> | |
#include <QQmlApplicationEngine> | |
#include <QSortFilterProxyModel> | |
#include <QDebug> | |
class MyModel : public QAbstractListModel | |
{ | |
Q_OBJECT | |
public: | |
explicit MyModel(QObject *parent = nullptr); | |
int rowCount(const QModelIndex &parent = QModelIndex()) const override; | |
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; | |
Q_INVOKABLE void addRow(); | |
private: | |
QVector<QString> mData; | |
}; | |
MyModel::MyModel(QObject *parent) : | |
QAbstractListModel(parent) | |
{ | |
for (int i = 0; i < 10; ++i) | |
mData.append(QString::fromLatin1("Item %1").arg(i + 1)); | |
} | |
int MyModel::rowCount(const QModelIndex &) const | |
{ | |
return mData.size(); | |
} | |
QVariant MyModel::data(const QModelIndex &index, int role) const | |
{ | |
if (index.row() < 0 || index.row() > rowCount()) { | |
return QVariant(); | |
} | |
qDebug() << objectName() << "asking for entry at row index" << index.row(); | |
switch (role) { | |
case Qt::DisplayRole: | |
return mData.at(index.row()); | |
} | |
return QVariant(); | |
} | |
void MyModel::addRow() | |
{ | |
qDebug() << "adding Test row"; | |
beginInsertRows(QModelIndex(), mData.size(), mData.size()); | |
mData.append("Test"); | |
endInsertRows(); | |
} | |
// Based on https://stackoverflow.com/a/29275072 | |
class ProxyModelNoneEntry : public QSortFilterProxyModel | |
{ | |
Q_OBJECT | |
public: | |
ProxyModelNoneEntry(QString entryText = tr("(None)"), QObject *parent = nullptr); | |
int rowCount(const QModelIndex &parent = QModelIndex()) const override; | |
/* lessThan() is not necessary for this model to work, but can be | |
implemented in a derived class if a custom sorting method is required. */ | |
// bool lessThan(const QModelIndex &left, const QModelIndex &right) const; | |
QModelIndex mapFromSource(const QModelIndex &sourceIndex) const override; | |
QModelIndex mapToSource(const QModelIndex &proxyIndex) const override; | |
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; | |
Qt::ItemFlags flags(const QModelIndex &index) const override; | |
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override; | |
QModelIndex parent(const QModelIndex &child) const override; | |
private: | |
QString mEntryText; | |
}; | |
ProxyModelNoneEntry::ProxyModelNoneEntry(QString entryText, QObject *parent) : | |
QSortFilterProxyModel(parent) | |
{ | |
mEntryText = entryText; | |
} | |
int ProxyModelNoneEntry::rowCount(const QModelIndex &/*parent*/) const | |
{ | |
return QSortFilterProxyModel::rowCount() + 1; | |
} | |
QModelIndex ProxyModelNoneEntry::mapFromSource(const QModelIndex &sourceIndex) const | |
{ | |
if (!sourceIndex.isValid()) return QModelIndex(); | |
else if (sourceIndex.parent().isValid()) return QModelIndex(); | |
return createIndex(sourceIndex.row()+1, sourceIndex.column()); | |
} | |
QModelIndex ProxyModelNoneEntry::mapToSource(const QModelIndex &proxyIndex) const | |
{ | |
if (!proxyIndex.isValid()) return QModelIndex(); | |
else if (proxyIndex.row() == 0) return QModelIndex(); | |
return sourceModel()->index(proxyIndex.row() - 1, proxyIndex.column()); | |
} | |
QVariant ProxyModelNoneEntry::data(const QModelIndex &index, int role) const | |
{ | |
if (!index.isValid()) return QVariant(); | |
if (index.row() == 0) { | |
if (role == Qt::DisplayRole) | |
return mEntryText; | |
else | |
return QVariant(); | |
} | |
return QSortFilterProxyModel::data(createIndex(index.row(),index.column()), role); | |
} | |
Qt::ItemFlags ProxyModelNoneEntry::flags(const QModelIndex &index) const | |
{ | |
if (!index.isValid()) return Qt::NoItemFlags; | |
if (index.row() == 0) return Qt::ItemIsSelectable | Qt::ItemIsEnabled; | |
return QSortFilterProxyModel::flags(createIndex(index.row(),index.column())); | |
} | |
QModelIndex ProxyModelNoneEntry::index(int row, int column, const QModelIndex &/*parent*/) const | |
{ | |
if (row > rowCount()) | |
return QModelIndex(); | |
return createIndex(row, column); | |
} | |
QModelIndex ProxyModelNoneEntry::parent(const QModelIndex &/*child*/) const | |
{ | |
return QModelIndex(); | |
} | |
int main(int argc, char *argv[]) | |
{ | |
QGuiApplication app(argc, argv); | |
qmlRegisterType<ProxyModelNoneEntry>("App", 1, 0, "ProxyModelNoneEntry"); | |
qmlRegisterType<MyModel>("App", 1, 0, "MyModel"); | |
qmlRegisterAnonymousType<QAbstractItemModel>("App", 1); | |
QQmlApplicationEngine engine; | |
const QUrl url(QStringLiteral("qrc:/main.qml")); | |
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, | |
&app, [url](QObject *obj, const QUrl &objUrl) { | |
if (!obj && url == objUrl) | |
QCoreApplication::exit(-1); | |
}, Qt::QueuedConnection); | |
engine.load(url); | |
return app.exec(); | |
} | |
#include "main.moc" |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import QtQuick 2.15 | |
import QtQuick.Controls 2.15 | |
import App 1.0 | |
ApplicationWindow { | |
width: 640 | |
height: 480 | |
visible: true | |
title: qsTr("Hello World") | |
Timer { | |
running: true | |
interval: 1000 | |
onTriggered: { | |
comboBox.model.sourceModel.addRow() | |
} | |
} | |
ComboBox { | |
id: comboBox | |
textRole: "display" | |
model: ProxyModelNoneEntry { | |
sourceModel: MyModel {} | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment