Last active
October 11, 2020 17:44
-
-
Save mitchcurtis/42e50d378d24e35a8396607e94a08f97 to your computer and use it in GitHub Desktop.
ProxyModelNoneEntry with QAbstractProxyModel
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 <QAbstractProxyModel> | |
#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 QAbstractProxyModel | |
{ | |
Q_OBJECT | |
public: | |
ProxyModelNoneEntry(QString entryText = tr("(None)"), QObject *parent = nullptr); | |
int columnCount(const QModelIndex &parent = QModelIndex()) const override; | |
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) : | |
QAbstractProxyModel(parent) | |
{ | |
mEntryText = entryText; | |
} | |
int ProxyModelNoneEntry::columnCount(const QModelIndex &/*parent*/) const | |
{ | |
return 1; | |
} | |
int ProxyModelNoneEntry::rowCount(const QModelIndex &parent) const | |
{ | |
qDebug() << "ProxyModelNoneEntry rowCount" << sourceModel()->rowCount(parent) + 1; | |
return sourceModel() ? sourceModel()->rowCount(parent) + 1 : 0; | |
} | |
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 (!sourceModel() || !index.isValid()) | |
return QVariant(); | |
qDebug() << "ProxyModelNoneEntry data" << index.row() << role; | |
if (index.row() == 0) { | |
if (role == Qt::DisplayRole) | |
return mEntryText; | |
else | |
return QVariant(); | |
} | |
const QModelIndex sourceIndex = mapToSource(index); | |
if (index.isValid() && !sourceIndex.isValid()) | |
return QVariant(); | |
return sourceModel()->data(sourceIndex, role); | |
} | |
Qt::ItemFlags ProxyModelNoneEntry::flags(const QModelIndex &index) const | |
{ | |
if (!index.isValid()) | |
return Qt::NoItemFlags; | |
if (index.row() == 0) | |
return Qt::ItemIsSelectable | Qt::ItemIsEnabled; | |
QModelIndex sourceIndex = mapToSource(index); | |
return sourceModel()->flags(sourceIndex); | |
} | |
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