I have implemented QAbstractItemModel as a C++ class and I'm trying to use it as a model for QComboBox. The model is storing QList of QStrings, which are names of project apps INI files. I can print out the list into console, and I'am certainly getting the right list of files. However I'm getting an error Unable to assign [undefined] to QString.
Can you please help me, what am I doing wrong?
LcuModel.cpp
#include "LcuModel.h"
#include "logging/LoggingQtCategories.h"
#include <QCoreApplication>
#include <QSettings>
#include <QFileInfo>
#include <QDir>
LcuModel::LcuModel(QObject *parent)
: QAbstractItemModel(parent)
{
QSettings settings;
QFileInfo fileInfo(settings.fileName());
QDir directory(fileInfo.absolutePath());
iniFiles_ = directory.entryList({"*.ini"},QDir::Files);
if (iniFiles_.empty())
{
qCWarning(lcLcu) << "No ini files were found.";
}
qCInfo(lcLcu) << iniFiles_; //this prints out all the files to console, so the list is certainly not empty
}
QModelIndex LcuModel::index(int row, int column, const QModelIndex &parent) const
{
Q_UNUSED(row)
Q_UNUSED(column)
Q_UNUSED(parent)
return QModelIndex();
}
QModelIndex LcuModel::parent(const QModelIndex &index) const
{
Q_UNUSED(index)
return QModelIndex();
}
int LcuModel::rowCount(const QModelIndex & parent) const {
Q_UNUSED(parent)
return iniFiles_.count();
}
int LcuModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return 1;
}
QVariant LcuModel::data(const QModelIndex & index, int role) const
{
Q_UNUSED(role);
int row = index.row();
qCInfo(lcLcu) << QString::number(row) << " ";
if (row < 0 || row >= iniFiles_.count()) {
return QVariant();
}
return QVariant(iniFiles_.at( index.row() ));
}
QHash<int, QByteArray> LcuModel::roleNames() const
{
QHash<int, QByteArray> names;
names[textRole] = "fileName";
return names;
}
LcuModel.h
#ifndef LCUMODEL_H
#define LCUMODEL_H
#include <QAbstractItemModel>
class LcuModel : public QAbstractItemModel
{
Q_OBJECT
public:
explicit LcuModel(QObject *parent = nullptr);
enum {
textRole
};
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role) const override;
protected:
virtual QHash<int, QByteArray> roleNames() const override;
private:
QList<QString> iniFiles_;
};
#endif // LCUMODEL_H
LcuMain.qml
import QtQuick 2.12
import QtQuick.Controls 2.12
import project.lcu 1.0
Item {
id: lcuMain
LcuModel{
id:lcuModel
}
Component.onCompleted: {
console.info("Completed "+ comboBox.count + "items")
} //this gives me right number of items from the list
Column{
ComboBox{
id: comboBox
model: lcuModel
delegate: ItemDelegate
{
contentItem: Text {
text: fileName
}
}
onActivated: console.info(comboBox.currentText + comboBox.currentIndex) //it prints out an empty string
}
}
}
console output
18:02:25.543 [ info ] project.lcu: LcuModel::LcuModel - ("first.ini", "second.ini", "third.ini", "fourth.ini", "fifth.ini", "sixth.ini", "seventh.ini", "eight.ini", "nineth.ini")
18:02:25.616 [warning] unknown - ComboBox.qml:47:5: QML Connections: Cannot assign to non-existent property "onCountChanged"
18:02:25.675 [ info ] qml: onCompleted - 9
18:02:25.678 [warning] unknown - qrc:/LcuMain.qml:46:25: Unable to assign [undefined] to QString
It is unnecessary for the model to inherit from QAbstractItemModel, QAbstractListModel is enough so you don't have to implement multiple methods. On the other hand, you must establish the role that you want to show through textRole and in the delegate you must use modelData:
#ifndef LCUMODEL_H
#define LCUMODEL_H
#include <QAbstractListModel>
class LcuModel : public QAbstractListModel
{
Q_OBJECT
public:
enum {
textRole = Qt::UserRole
};
explicit LcuModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QHash<int, QByteArray> roleNames() const override;
private:
QStringList iniFiles_;
};
#endif // LCUMODEL_H
#include "lcumodel.h"
#include <QDir>
#include <QFileInfo>
#include <QSettings>
LcuModel::LcuModel(QObject *parent)
: QAbstractListModel(parent)
{
QSettings settings;
QFileInfo fileInfo(settings.fileName());
QDir directory(fileInfo.absolutePath());
iniFiles_ = directory.entryList({"*.ini"}, QDir::Files);
}
int LcuModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
return iniFiles_.length();
}
QVariant LcuModel::data(const QModelIndex &index, int role) const
{
if(!checkIndex(index)){
return QVariant();
}
if(role == textRole){
return iniFiles_.at(index.row());
}
return QVariant();
}
QHash<int, QByteArray> LcuModel::roleNames() const
{
QHash<int, QByteArray> names;
names[textRole] = "fileName";
return names;
}
import QtQuick 2.12
import QtQuick.Controls 2.12
import project.lcu 1.0
Item{
id: lcuMain
LcuModel{
id:lcuModel
}
Column{
ComboBox{
id: comboBox
model: lcuModel
textRole: "fileName"
delegate: ItemDelegate{
text: modelData
width: parent.width
}
}
}
}
Related
I am trying to update a model in a QML ListView from a cpp file..
Here is my implemenation. I copied evrything to this therfore it will be a little bit bigger from code size.
this is my model implementation albummodel.h
#include <QAbstractListModel>
#include <QStringList>
#include <QQmlListProperty>
class Album
{
public:
Album(const QString &type, const QString &size);
QString type() const;
QString size() const;
private:
QString m_type;
QString m_size;
};
class AlbumModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(QQmlListProperty<QObject> myModel NOTIFY listChanged)
public:
enum AlbumRoles {
TypeRole = Qt::UserRole + 1,
SizeRole
};
AlbumModel(QObject *parent = 0);
//QQmlListProperty<QObject> getList();
void addAlbum(const Album &album);
int rowCount(const QModelIndex & parent = QModelIndex()) const;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
protected:
QHash<int, QByteArray> roleNames() const;
private:
QList<Album> m_albums;
signals:
void listChanged();
#include <QAbstractListModel>
#include <QStringList>
#include <QQmlListProperty>
class Album
{
public:
Album(const QString &type, const QString &size);
QString type() const;
QString size() const;
private:
QString m_type;
QString m_size;
};
class AlbumModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(QQmlListProperty<QObject> myModel NOTIFY listChanged)
public:
enum AlbumRoles {
TypeRole = Qt::UserRole + 1,
SizeRole
};
AlbumModel(QObject *parent = 0);
//QQmlListProperty<QObject> getList();
void addAlbum(const Album &album);
int rowCount(const QModelIndex & parent = QModelIndex()) const;
QVariant data(const QModelIndex & index, int role = Qt::DisplayRole) const;
protected:
QHash<int, QByteArray> roleNames() const;
private:
QList<Album> m_albums;
signals:
void listChanged();
};
This is my albummodel.cpp
#include "albummodel_mediaplayer.h"
Album::Album(const QString &type, const QString &size)
: m_type(type), m_size(size)
{
}
QString Album::type() const
{
return m_type;
}
QString Album::size() const
{
return m_size;
}
AlbumModel::AlbumModel(QObject *parent)
: QAbstractListModel(parent)
{
}
void AlbumModel::addAlbum(const Album &album)
{
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_albums << album;
endInsertRows();
emit listChanged();
}
int AlbumModel::rowCount(const QModelIndex & parent) const {
Q_UNUSED(parent);
return m_albums.count();
}
QVariant AlbumModel::data(const QModelIndex & index, int role) const {
if (index.row() < 0 || index.row() >= m_albums.count())
return QVariant();
const Album &Album = m_albums[index.row()];
if (role == TypeRole)
return Album.type();
else if (role == SizeRole)
return Album.size();
return QVariant();
}
QHash<int, QByteArray> AlbumModel::roleNames() const {
QHash<int, QByteArray> roles;
roles[TypeRole] = "type";
roles[SizeRole] = "size";
return roles;
}
/*QQmlListProperty<QObject> AlbumModel::getList(){
return QQmlListProperty<QObject>(this, *list);
}*/
and my qml file
import AlbumModel 1.0
ListView {
model: AlbumModel.myModel
delegate: playListThumbnail
Component {
id: playListThumbnail
Item {
Text {
id: albumTitleText
text: type//item_title
}}
....
}
I added the main Programm Code. Hope this is enough for a mvp
Main.cpp
void main() {
qmlRegisterType<AlbumModel>("AlbumModel",1,0,"AlbumModel");
Album g("test", "test");
AlbumModel h();
h.addAlbum(g);
}
But the model isn't updated. Which signal did i miss?
I'm trying to show a simple XML file in a QML treeView through the QAbstractItemModel class, but I can't find any decent tutorial on how to do so online. The best I managed to find is a tutorial about how to do it in QWidget, but I want to do it in QML. I tried anyway with all the bits I could find here and there but couldn't even manage to get a tree to show up.
Code compiles, but my model is null. I'm not even sure if I'm actually reading my XML file.
There's very likely a lot of things I am missing or doing wrong. Can anyone help ?
DomItem.h
#ifndef DOMITEM_H
#define DOMITEM_H
#include <QDomNode>
#include <QHash>
class DomItem
{
public:
DomItem(const QDomNode &node, int row, DomItem *parent = nullptr);
~DomItem();
DomItem *child(int i);
DomItem *parent();
QDomNode node() const;
int row() const;
private:
QDomNode domNode;
QHash<int, DomItem *> childItems;
DomItem *parentItem;
int rowNumber;
};
#endif // DOMITEM_H
DomItem.cpp
#include "DomItem.h"
DomItem::DomItem(const QDomNode &node, int row, DomItem *parent)
: domNode(node),
parentItem(parent),
rowNumber(row)
{
}
DomItem::~DomItem()
{
qDeleteAll(childItems);
}
DomItem *DomItem::parent()
{
return parentItem;
}
int DomItem::row() const
{
return rowNumber;
}
QDomNode DomItem::node() const
{
return domNode;
}
DomItem *DomItem::child(int i)
{
DomItem *childItem = childItems.value(i);
if (childItem)
return childItem;
// if child does not yet exist, create it
if (i >= 0 && i < domNode.childNodes().count()) {
QDomNode childNode = domNode.childNodes().item(i);
childItem = new DomItem(childNode, i, this);
childItems[i] = childItem;
}
return childItem;
}
DomModel.h
#ifndef DOMMODEL_H
#define DOMMODEL_H
#include <QObject>
#include <QModelIndex>
#include <QAbstractItemModel>
#include <QDomDocument>
#include <QFile>
#include "DomItem.h"
class DomModel : public QAbstractItemModel
{
Q_OBJECT
public:
enum DomModelRoles
{
DomModelRoleName = Qt::UserRole + 1,
DomModelRoleAttributes,
DomModelRoleValue
};
explicit DomModel(const QDomDocument &document, QObject *parent = nullptr);
~DomModel();
QVariant data(const QModelIndex &index, int role) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const override;
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &child) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
void loadXml(QString xmlFilePath);
void reload();
QHash<int, QByteArray> roleNames() const override;
private:
QDomDocument domDocument;
DomItem *rootItem;
QString xmlSource;
};
#endif // DOMMODEL_H
DomModel.cpp
#include "DomModel.h"
DomModel::DomModel(const QDomDocument &document, QObject *parent)
: QAbstractItemModel(parent),
domDocument(document)
{
rootItem = new DomItem(domDocument, 0);
}
DomModel::~DomModel()
{
delete rootItem;
}
int DomModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return 3;
}
Qt::ItemFlags DomModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::NoItemFlags;
return QAbstractItemModel::flags(index);
}
QVariant DomModel::headerData(int section, Qt::Orientation orientation,
int role) const
{
if (orientation == Qt::Horizontal && role == Qt::DisplayRole) {
switch (section) {
case 0:
return tr("Name");
case 1:
return tr("Attributes");
case 2:
return tr("Value");
default:
break;
}
}
return QVariant();
}
QModelIndex DomModel::index(int row, int column, const QModelIndex &parent) const
{
if (!hasIndex(row, column, parent))
return QModelIndex();
DomItem *parentItem;
if (!parent.isValid())
parentItem = rootItem;
else
parentItem = static_cast<DomItem*>(parent.internalPointer());
DomItem *childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
return QModelIndex();
}
int DomModel::rowCount(const QModelIndex &parent) const
{
if (parent.column() > 0)
return 0;
DomItem *parentItem;
if (!parent.isValid())
parentItem = rootItem;
else
parentItem = static_cast<DomItem*>(parent.internalPointer());
return parentItem->node().childNodes().count();
}
QModelIndex DomModel::parent(const QModelIndex &child) const
{
if (!child.isValid())
return QModelIndex();
DomItem *childItem = static_cast<DomItem*>(child.internalPointer());
DomItem *parentItem = childItem->parent();
if (!parentItem || parentItem == rootItem)
return QModelIndex();
return createIndex(parentItem->row(), 0, parentItem);
}
QVariant DomModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (role != Qt::DisplayRole)
return QVariant();
const DomItem *item = static_cast<DomItem*>(index.internalPointer());
const QDomNode node = item->node();
switch (role)
{
case DomModelRoleName:
return node.nodeName();
case DomModelRoleAttributes:
{
const QDomNamedNodeMap attributeMap = node.attributes();
QStringList attributes;
for (int i = 0; i < attributeMap.count(); ++i) {
QDomNode attribute = attributeMap.item(i);
attributes << attribute.nodeName() + "=\""
+ attribute.nodeValue() + '"';
}
return attributes.join(' ');
}
case DomModelRoleValue:
return node.nodeValue().split('\n').join(' ');
default:
break;
}
return QVariant();
}
void DomModel::loadXml(QString xmlFilePath)
{
xmlFilePath.replace("file:///","");
// on parse le xml de l'environnement
QFile file(xmlFilePath);
if (!file.open(QIODevice::ReadOnly| QFile::Text)){
//QMessageBox::critical(this, "ParserFichierXML", "Error");
}
else{
domDocument.clear();
if (!domDocument.setContent(&file)) {
//QMessageBox::critical(this, "ParserFichierXML", "Error");
}
file.close();
}
reload();
}
void DomModel::reload()
{
beginResetModel();
delete rootItem;
rootItem = new DomItem(domDocument, 0,false);
endResetModel();
}
QHash<int, QByteArray> DomModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[DomModelRoleName] = "Name";
roles[DomModelRoleAttributes] = "Attributes";
roles[DomModelRoleValue] = "Value";
return roles;
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QDomDocument>
#include <QQmlContext>
#include "DomModel.h"
int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
QGuiApplication app(argc, argv);
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);
QQmlContext *ctx = engine.rootContext();
QFile file("./test.xml");
if (file.open(QIODevice::ReadOnly))
{
QDomDocument document;
if (document.setContent(&file))
{
DomModel *model = new DomModel(document);
ctx->setContextProperty("theModel", model);
}
}
file.close();
engine.load(url);
return app.exec();
}
main.qml
import QtQuick 2.7
import QtQuick.Window 2.2
import QtQuick.Layouts 1.3
import QtQuick.Dialogs 1.2
import QtLocation 5.3
import QtQuick.Controls 1.4
import QtQuick.Controls 2.0
import QtQuick.Controls.Styles 1.4
import QtQml 2.0
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
TreeView
{
id:treeView
anchors.fill: parent
model: theModel
itemDelegate: TreeDelegate
{
id: treeDeleg
}
style: TreeViewStyle
{
id: styleTree
}
TableViewColumn
{
id:column1
role: "Name"
title: "Name"
width: 450
}
TableViewColumn
{
id:column3
role: "Value"
title: "Value"
width: 400
}
Component.onCompleted:
{
treeView.model = Qt.binding(function()
{
if (typeof theModel !== "undefined")
{
console.log("Model loaded");
return theModel;
}
else
{
console.log("Couldn't load model");
return null;
}
});
}
}
}
TreeDelegate.qml
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.3
import QtQuick 2.7
import QtQml 2.0
Item
{
id: item
width : parent.width
height: 25
TextEdit
{
id: text1
font.pixelSize: 14
readOnly: true
focus: false
width : parent.width
height: 25 * lineCount
anchors.left: parent.left
wrapMode: TextEdit.Wrap
text: styleData.value
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
}
}
I am trying to add large sets of data in QTableView. As there is huge set of data, in order to avoid freezing the application, I am trying to use a QAbstractTableModel to not showthe whole dataset immediately, but only what is necessary. Based on the QT example for this (HERE), I have the following class:
FileListModel.cpp
#include "filelistmodel.h"
#include <QGuiApplication>
#include <QDir>
#include <QPalette>
#include "qdebug.h"
FileListModel::FileListModel(QObject *parent)
: QAbstractTableModel(parent), fileCount(0) //edit
{}
int FileListModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : fileCount;
}
QVariant FileListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
{
return QVariant();
}
if (index.row() >= fileList.size() || index.row() < 0)
{
return QVariant();
}
if (role == Qt::DisplayRole)
{
return fileList.at(index.row());
}
return QVariant();
}
bool FileListModel::canFetchMore(const QModelIndex &parent) const
{
if (parent.isValid())
{
return false;
}
return (fileCount < fileList.size());
}
int FileListModel::columnCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : colCount;
}
void FileListModel::fetchMore(const QModelIndex &parent)
{
if (parent.isValid())
{
return;
}
int remainder = fileList.size() - fileCount;
int itemsToFetch = qMin(100, remainder);
if (itemsToFetch <= 0)
{
return;
}
beginInsertRows(QModelIndex(), fileCount, fileCount + itemsToFetch - 1);
qDebug()<< "Qmodelindex "<< QModelIndex()<< "filecount "<< fileCount <<"filecount + itemtofetch "<<fileCount + itemsToFetch - 1;
fileCount += itemsToFetch;
endInsertRows();
}
void FileListModel::setColumnNumber(const int x) //edit
{
colCount = x;
}
void FileListModel::setDataToList(const QList<float> &data)
{
beginResetModel();
fileList = data;
fileCount = 0;
endResetModel();
}
FileListModel.h
#ifndef FILELISTMODEL_H
#define FILELISTMODEL_H
#include <QAbstractTableModel>
#include <QStringList>
class FileListModel : public QAbstractTableModel //edit
{
Q_OBJECT
public:
FileListModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override; //edit
void setColumnNumber(const int );
public slots:
void setDataToList(const QList<float>&);
protected:
bool canFetchMore(const QModelIndex &parent) const override;
void fetchMore(const QModelIndex &parent) override;
private:
QList<float> fileList;
int fileCount;
int colCount;//edit
};
#endif // FILELISTMODEL_H
In my window, I have a QTableView and 5 QList<float>, each representing a column.
I proceed this way to add the data in my QTableView:
FileListModel *model=new FileListModel(this);
model->setColumnNumber(5); //edit
model->setDataToList(list1);
model->setDataToList(list2);
model->setDataToList(list3);
model->setDataToList(list4);
model->setDataToList(list5);
tableview->setModel(model)
However, the last list added (list5) replace the previous one and I have only the same text in all the columns. I am aware that I need to write the needed code to add columns. But to be honest, I am not knowing very well the QAbstract classes, and have no idea how to proceed. I would be grateful if you could provide me some hints or an example on how to modify my code in order to add columns in my model.
I found how to proceed by storing my data in a QList>.
Please find below a working code that can probably be improved:
CPP FILE
#include "filelistmodel.h"
#include <QGuiApplication>
#include <QDir>
#include <QPalette>
#include "qdebug.h"
FileListModel::FileListModel(QObject *parent)
: QAbstractTableModel(parent), rowNumber(0)
{}
int FileListModel::rowCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : rowNumber;
}
int FileListModel::columnCount(const QModelIndex &parent) const
{
return parent.isValid() ? 0 : colNumber;
}
void FileListModel::setColumnNumber(const int x)
{
colNumber = x;
}
QVariant FileListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
{
return QVariant();
}
if (index.row() >= fileList[0].size() || index.row() < 0)
{
return QVariant();
}
if (role == Qt::DisplayRole)
{
return fileList[index.column()][index.row()];
}
return QVariant();
}
bool FileListModel::canFetchMore(const QModelIndex &parent) const
{
if (parent.isValid())
{
return false;
}
return (rowNumber < fileList[0].size());
}
void FileListModel::fetchMore(const QModelIndex &parent)
{
if (parent.isValid())
{
return;
}
int remainder = fileList[0].size() - rowNumber;
int itemsToFetch = qMin(100, remainder);
if (itemsToFetch <= 0)
{
return;
}
beginInsertRows(QModelIndex(), rowNumber, rowNumber + itemsToFetch - 1);
rowNumber += itemsToFetch;
endInsertRows();
}
void FileListModel::setDataToTable(const QList<QList<float>> &data)
{
beginResetModel();
fileList = data;
rowNumber = 0;
endResetModel();
}
H FILE
#ifndef FILELISTMODEL_H
#define FILELISTMODEL_H
#include <QAbstractListModel>
#include <QStringList>
class FileListModel : public QAbstractTableModel
{
Q_OBJECT
public:
FileListModel(QObject *parent = nullptr);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
void setColumnNumber(const int );
void setDataToTable(const QList<QList<float>>&);
protected:
bool canFetchMore(const QModelIndex &parent) const override;
void fetchMore(const QModelIndex &parent) override;
private:
QList<QList<float>> fileList;
int rowNumber;
int colNumber;
};
#endif // FILELISTMODEL_H
BUILDING MODEL
FileListModel *pModel =new FileListModel(this);
QList<QList<float>> a;
pModel->setColumnNumber(5);
a.append(qlist1);
a.append(qlist2);
a.append(qlist3);
a.append(qlist4);
a.append(qlist5);
pModel->setDataToTable(a);
I am trying to view a list of c++ models in qml by subclassing QAbstractListModel following this tutorial Models and Views: AbstractItemModel Example
Here is my implementation:
Item model class
class User
{
private:
QString m_macAddr;
QString m_firstName;
QString m_lastName;
public:
User();
User(const QString &mac);
QString macAddr() const;
void setMacAddr(QString &mac);
};
User::User()
{}
User::User(const QString &mac){
m_macAddr = mac;
}
QString User::macAddr() const{
return m_macAddr;
}
void User::setMacAddr(QString &mac){
if(mac == m_macAddr)
return;
m_macAddr = mac;
// emit macAddrChanged();
}
QAbstractListModel subclass
class UserListModel : public QAbstractListModel
{
Q_OBJECT
public:
// User model roles
enum roles{
macRole = Qt::UserRole + 1
};
UserListModel(QObject *parent = nullptr);
QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;
QModelIndex getIndex(int r, int c, void *p);
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
void addUser(const User &user);
private:
QList<User> m_users;
protected:
QHash<int, QByteArray> rolesNames() const;
};
// Class inplementation.
UserListModel::UserListModel(QObject *parent)
: QAbstractListModel(parent)
{
}
void UserListModel::addUser(const User &user){
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_users << user;
endInsertRows();
}
int UserListModel::rowCount(const QModelIndex &parent) const
{
return m_users.count();
}
QVariant UserListModel::data(const QModelIndex &index, int role) const
{
if (index.row() < 0 || index.row() >= rowCount())
return QVariant();
const User &user = m_users[index.row()];
if(role == macRole){
return user.macAddr();
}
return QVariant();
}
QModelIndex UserListModel::index(int row, int column, const QModelIndex &parent) const
{
return parent;
}
QModelIndex UserListModel::parent(const QModelIndex &index) const
{
return index;
}
QModelIndex UserListModel::getIndex(int r, int c, void *p) {
return this->createIndex(r, c, p);
}
QHash<int, QByteArray> UserListModel::rolesNames() const {
QHash<int, QByteArray> roles;
roles[macRole] = "mac";
return roles;
}
main.cpp
QQmlApplicationEngine engine;
QString mac = "12:3e:3w:4r:33";
userlistModel->addUser(User(mac));
userlistModel->addUser(User(mac));
userlistModel->addUser(User(mac));
userlistModel->addUser(User(mac));
engine.rootContext()->setContextProperty("usersModel", userlistModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
QModelIndex id = userlistModel->getIndex(1, 0, 0);
QVariant v1 = userlistModel->data(id, Qt::UserRole + 1);
qDebug() << "===========" << v1.toString();
controller::DatabaseService<SqliteDB> *sqliteDb = new controller::DatabaseService<SqliteDB>();
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
QML
ListView{
id: listView
anchors.fill: parent
model:usersModel
delegate: Component { HorizontalListItem{mac: mac}}
}
The Problem is :
In main function I am adding 4 models to the list model but, They are shown in qml without data. althought, I am trying to view mac role.
what I tried
I tried to add a breakpoint inside methodes rolesNames() and data()
but, It seems that the compiler is not getting inside anyone of them.
I tried to invoke data() method in main function and it returns the desired data.
It is not necessary that you override the index, or parent methods, nor do you create the getIndex method. In your case you need to implement the roleNames method:
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QAbstractListModel>
#include <QDebug>
class User
{
QString m_macAddr;
public:
User(){}
User(const QString &mac): m_macAddr(mac){}
QString macAddr() const{return m_macAddr;}
void setMacAddr(QString &mac){m_macAddr = mac;}
};
class UserListModel : public QAbstractListModel
{
public:
enum roles{
macRole = Qt::UserRole + 1
};
explicit UserListModel(QObject *parent = nullptr)
: QAbstractListModel(parent){}
int rowCount(const QModelIndex &parent = QModelIndex()) const override {
if (parent.isValid())
return 0;
return m_users.count();
}
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override {
if (!index.isValid())
return QVariant();
if (index.row() < 0 || index.row() >= rowCount())
return QVariant();
const User &user = m_users[index.row()];
if(role == macRole)
return user.macAddr();
return QVariant();
}
QHash<int, QByteArray> roleNames() const override{
QHash<int, QByteArray> roles;
roles[macRole] = "mac";
return roles;
}
void addUser(const User &user){
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_users << user;
endInsertRows();
}
private:
QList<User> m_users;
};
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
UserListModel userlistModel;
QString mac = "12:3e:3w:4r:33";
userlistModel.addUser(User(mac));
userlistModel.addUser(User(mac));
userlistModel.addUser(User(mac));
userlistModel.addUser(User(mac));
QModelIndex ix = userlistModel.index(1, 0);
QVariant v = userlistModel.data(ix, UserListModel::macRole);
qDebug() << "===========" << v.toString();
engine.rootContext()->setContextProperty("usersModel", &userlistModel);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
if (engine.rootObjects().isEmpty())
return -1;
return app.exec();
}
main.qml
import QtQuick 2.9
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ListView{
anchors.fill: parent
model:usersModel
delegate: Component
{
Text{
text: model.mac
}
}
}
}
I've created Proxy model by subclassing QAbstractProxyModel and connected it as a model to my view. I also set up source model for this proxy model. Unfortunately something is wrong because I'm not getting anything displayed on my listView (it works perfectly when I have my model supplied as a model to view but when I supply this proxy model it just doesn't work). Here are some snippets from my code:
#ifndef FILES_PROXY_MODEL_H
#define FILES_PROXY_MODEL_H
#include <QAbstractProxyModel>
#include "File_List_Model.h"
class File_Proxy_Model: public QAbstractProxyModel
{
public:
explicit File_Proxy_Model(File_List_Model* source_model)
{
setSourceModel(source_model);
}
virtual QModelIndex mapFromSource(const QModelIndex & sourceIndex) const
{
return index(sourceIndex.row(),sourceIndex.column());
}
virtual QModelIndex mapToSource(const QModelIndex & proxyIndex) const
{
return index(proxyIndex.row(),proxyIndex.column());
}
virtual int columnCount(const QModelIndex & parent = QModelIndex()) const
{
return sourceModel()->columnCount();
}
virtual int rowCount(const QModelIndex & parent = QModelIndex()) const
{
return sourceModel()->rowCount();
}
virtual QModelIndex index(int row, int column, const QModelIndex & parent = QModelIndex()) const
{
return createIndex(row,column);
}
virtual QModelIndex parent(const QModelIndex & index) const
{
return QModelIndex();
}
};
#endif // FILES_PROXY_MODEL_H
//and this is a dialog class:
Line_Counter::Line_Counter(QWidget *parent) :
QDialog(parent), model_(new File_List_Model(this)),
proxy_model_(new File_Proxy_Model(model_)),
sel_model_(new QItemSelectionModel(proxy_model_,this))
{
setupUi(this);
setup_mvc_();
}
void Line_Counter::setup_mvc_()
{
listView->setModel(proxy_model_);
listView->setSelectionModel(sel_model_);
}
mapToSource should return an index from the source model:
virtual QModelIndex mapToSource(const QModelIndex & proxyIndex) const
{
return sourceModel()->index(proxyIndex.row(),proxyIndex.column());
}
I tested with that code:
#include <QtGui>
#include "file_proxy_model.h"
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QDir dir(QDesktopServices::storageLocation(QDesktopServices::HomeLocation));
File_List_Model model(dir.entryList());
File_Proxy_Model proxy(&model);
QListView listView;
listView.setModel(&proxy);
listView.show();
return a.exec();
}
// In "File_List_Model.h"
class File_List_Model : public QStringListModel
{
public:
explicit File_List_Model(const QStringList & list, QObject *parent = 0)
: QStringListModel(list, parent)
{
}
};