Creating listview from QQuickItem in C++ - qt

I am trying to make a listview component using QQuickItem and load its model using QAbstractListModel. Below are the steps which i tried.
listviewComponent.qml
ListView {
required model
delegate: Text {
required property string type
required property string size
text: type + ", " + size
}
}
Model.h
class Model
{
public:
Model(const QString& type, const QString& size);
QString type() const;
QString size() const;
private:
QString m_type;
QString m_size;
};
class CustomModel : public QAbstractListModel
{
Q_OBJECT
public:
enum Roles {
TypeRole = Qt::UserRole + 1,
SizeRole
};
CustomModel(QObject* parent = 0);
void addElement(const Model& pElement);
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<Model> m_list;
};
Model.cpp
Model::Model(const QString& type, const QString& size)
: m_type(type), m_size(size)
{
}
QString Model::type() const
{
return m_type;
}
QString Model::size() const
{
return m_size;
}
CustomModel::CustomModel(QObject* parent)
: QAbstractListModel(parent)
{
}
void CustomModel::addElement(const Model &pElement)
{
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_list << pElement;
endInsertRows();
}
int CustomModel::rowCount(const QModelIndex& parent) const {
Q_UNUSED(parent);
return m_list.count();
}
QVariant CustomModel::data(const QModelIndex& index, int role) const {
if (index.row() < 0 || index.row() >= m_list.count())
return QVariant();
const Model& mod = m_list[index.row()];
if (role == TypeRole)
return mod.type();
else if (role == SizeRole)
return mod.size();
return QVariant();
}
QHash<int, QByteArray> CustomModel::roleNames() const {
QHash<int, QByteArray> roles;
roles[TypeRole] = "type";
roles[SizeRole] = "size";
return roles;
}
Myclass.h
class myclass : public QObject
{
Q_OBJECT
public:
myclass();
inline int createUI(QQmlApplicationEngine &engine){
QQuickWindow *window = qobject_cast<QQuickWindow*>(engine.rootObjects().at(0));
if (!window) {
qFatal("Error: Your root item has to be a window.");
return -1;
}
QQuickItem *root = window->contentItem();
window->setWidth(600);
window->setHeight(500);
QQmlComponent listviewComp(&engine, QUrl(QStringLiteral("qrc:/listviewComponent.qml")));
CustomModel model;
model.addElement(Model("Wolf", "Medium"));
model.addElement(Model("Polar bear", "Large"));
model.addElement(Model("Quoll", "Small"));
QQuickItem *listview = qobject_cast<QQuickItem*>(listviewComp.createWithInitialProperties({ {"model", QVariant::fromValue(&model)} }));
QQmlEngine::setObjectOwnership(listview, QQmlEngine::CppOwnership);
listview->setParentItem(root);
listview->setParent(&engine);
listview->setProperty("objectName", "lv");
listview->setWidth(200);
listview->setHeight(100);
listview->setX(250);
listview->setY(30);
window->show();
return 0;
}
};
main.cpp
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(QStringLiteral("qrc:/main.qml"));
engine.load(url);
QQmlContext *item = engine.rootContext();
myclass myClass;
item->setContextProperty("_myClass", &myClass);
myClass.createUI(engine);
return app.exec();
}
Problem: Listview is getting displayed but with only one row, but there are 3 rows added in CustomModel. I am assuming some problem with createWithInitialProperties, but couldnt able to crack it.

The problem is caused because "model" is a local variable that will be destroyed as soon as createUI is finished executing, and what you see as the first row is just a cache, you shouldn't actually see a row (it looks like a bug). The solution is to use the heap memory:
// ...
CustomModel *model = new CustomModel(window);
model->addElement(Model("Wolf", "Medium"));
model->addElement(Model("Polar bear", "Large"));
model->addElement(Model("Quoll", "Small"));
QQuickItem *listview = qobject_cast<QQuickItem*>(listviewComp.createWithInitialProperties({ {"model", QVariant::fromValue(model)} }));
// ...

Related

how to port a QAbstractItemModel to QtQuick (without defining ItemDelegate)

I have a QAbstractItemModel tree model for a Qt3D Entity tree:
qt3dentitytreemodel.h:
#define QT3DENTITYTREEMODEL_H
#include <QAbstractItemModel>
#include <Qt3DCore/QEntity>
class Qt3DEntityTreeModel : public QAbstractItemModel
{
Q_OBJECT
public:
Q_PROPERTY(Qt3DCore::QEntity * rootEntity READ rootEntity WRITE setRootEntity NOTIFY rootEntityChanged)
explicit Qt3DEntityTreeModel(QObject *parent = nullptr);
void setRootEntity(Qt3DCore::QEntity *rootEntity);
Qt3DCore::QEntity * rootEntity() const;
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &child) const override;
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override;
int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;
Qt::ItemFlags flags(const QModelIndex &index) const override;
signals:
void rootEntityChanged(Qt3DCore::QEntity *rootEntity);
private:
Qt3DCore::QEntity *rootEntity_;
};
#endif // QT3DENTITYTREEMODEL_H
qt3dentitytreemodel.cpp:
#include "qt3dentitytreemodel.h"
Qt3DEntityTreeModel::Qt3DEntityTreeModel(QObject *parent)
: QAbstractItemModel(parent)
{
}
void Qt3DEntityTreeModel::setRootEntity(Qt3DCore::QEntity *rootEntity)
{
qDebug() << "Qt3DEntityTreeModel::setRootEntity" << rootEntity;
auto old = rootEntity_;
rootEntity_ = rootEntity;
if(rootEntity_ != old)
emit rootEntityChanged(rootEntity);
}
Qt3DCore::QEntity * Qt3DEntityTreeModel::rootEntity() const
{
return rootEntity_;
}
QModelIndex Qt3DEntityTreeModel::index(int row, int column, const QModelIndex &parent) const
{
if(!rootEntity_) return {};
if(column != 0) return {};
if(!parent.isValid())
{
if(row == 0) return createIndex(0, 0, rootEntity_);
}
else
{
auto entity = reinterpret_cast<Qt3DCore::QEntity*>(parent.internalPointer());
if(!entity) return {};
return createIndex(row, column, entity->childNodes().at(row));
}
return {};
}
QModelIndex Qt3DEntityTreeModel::parent(const QModelIndex &child) const
{
if(!rootEntity_) return {};
if(!child.isValid()) return {};
auto entity = reinterpret_cast<Qt3DCore::QEntity*>(child.internalPointer());
if(!entity) return {};
auto parent = entity->parentNode();
if(!parent) return {};
auto grandParent = parent->parentNode();
if(!grandParent) return createIndex(0, 0, parent);
return createIndex(grandParent->childNodes().indexOf(parent), 0, parent);
}
QVariant Qt3DEntityTreeModel::data(const QModelIndex &index, int role) const
{
if(!rootEntity_) return {};
if(!index.isValid()) return {};
if(role != Qt::DisplayRole && role != DisplayRole) return {};
auto entity = reinterpret_cast<Qt3DCore::QEntity*>(index.internalPointer());
if(!entity) return {};
QString data = entity->metaObject()->className();
if(!entity->objectName().isEmpty())
data += QString(" \"%1\"").arg(entity->objectName());
return data;
}
QVariant Qt3DEntityTreeModel::headerData(int section, Qt::Orientation orientation, int role) const
{
return {};
}
int Qt3DEntityTreeModel::rowCount(const QModelIndex &parent) const
{
if(!parent.isValid()) return 1;
auto entity = reinterpret_cast<Qt3DCore::QEntity*>(parent.internalPointer());
if(!entity) return 0;
return entity->childNodes().count();
}
int Qt3DEntityTreeModel::columnCount(const QModelIndex &parent) const
{
return 1;
}
Qt::ItemFlags Qt3DEntityTreeModel::flags(const QModelIndex &index) const
{
return {};
}
which works fine when displayed in a QTreeView (QtWidgets):
auto treeView = new QTreeView();
auto treeModel = new Qt3DEntityTreeModel(treeView);
treeModel->setRootEntity(rootEntity);
treeView->setModel(treeModel);
treeView->resize(640, 480);
treeView->show();
however when used in a QtQuick Controls TreeView, I cannot see the item text, and I cannot even expand the root tree item:
Item {
...
Qt3DEntityTreeModel {
id: entityTreeModel
rootEntity: root
}
TreeView {
model: entityTreeModel
TableViewColumn {
title: "Name"
width: 200
}
}
Scene3D {
id: scene3d
Entity {
id: root
...
}
}
}
I also tried to explicitly define a role in Qt3DEntityTreeModel:
qt3dentitytreemodel.h:
enum Roles {
DisplayRole = Qt::UserRole + 1
};
QHash<int, QByteArray> roleNames() const override;
qt3dentitytreemodel.cpp:
QVariant Qt3DEntityTreeModel::data(const QModelIndex &index, int role) const
{
if(!rootEntity_) return {};
if(!index.isValid()) return {};
if(role != Qt::DisplayRole && role != DisplayRole) return {};
...
}
QHash<int, QByteArray> Qt3DEntityTreeModel::roleNames() const
{
QHash<int, QByteArray> result;
result.insert(DisplayRole, QByteArrayLiteral("display"));
return result;
}
and define the respective role property in the column of the QtQuick TreeView:
TreeView {
model: entityTreeModel
TableViewColumn {
title: "Name"
role: "display"
width: 200
}
}
but still shows nothing.
Is there something else to do to be able to use a custom abstract item model with QtQuick's TreeView?
I think I found the explanation: the model is created before the Qt3D entity tree is "ready".
If I create the model in C++ after the view is loaded, then set the model as a context property, it displays correctly in the QML's TreeView:
QQuickView view;
view.resize(500, 500);
view.setResizeMode(QQuickView::SizeRootObjectToView);
view.setSource(QUrl("qrc:/main.qml"));
auto rootObject = view.rootObject();
auto rootEntity = rootObject->findChild<Qt3DCore::QEntity*>("theRootEntity");
qDebug() << "rootEntity:" << rootEntity;
auto treeModel = new Qt3DEntityTreeModel(&app);
treeModel->setRootEntity(rootEntity);
view.rootContext()->setContextProperty("theModel", treeModel);
view.show();
The fundamental problem is that my model doesn't monitor updates to the Qt3D entity tree, and it does not reflect such updates.

change c++ QAbstractListModel values from Qml

this is my code
devicemodel.h
class Device
{
public:
Device(const int &nodeId ,const QString &type, const int &lampVoltage);
//![0]
QString type() const;
int lampVoltage() const;
int nodeId() const;
public:
QString m_type;
int m_lampVoltage;
int m_nodeId;
//![1]
};
class DeviceModel : public QAbstractListModel
{
Q_OBJECT
public:
enum DeviceRoles {
NodeIdRole = Qt::UserRole + 1,
TypeRole ,
LampVoltageRole
};
DeviceModel(QObject *parent = 0);
//![1]
void addDevice(const Device &Device);
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<Device> m_Devices;
//![2]
public slots :
void callFromQml(int index);
};
devicemodel.cpp
Device::Device(const int &nodeId ,const QString &type, const int &lampVoltage)
: m_nodeId(nodeId) , m_type(type), m_lampVoltage(lampVoltage)
{
}
QString Device::type() const
{
return m_type;
}
int Device::nodeId() const
{
return m_nodeId;
}
int Device::lampVoltage() const
{
return m_lampVoltage;
}
DeviceModel::DeviceModel(QObject *parent)
: QAbstractListModel(parent)
{
}
void DeviceModel::callFromQml(int index){
Device k= m_Devices.at(index);
qDebug() << k.type() << k.lampVoltage();
k.m_lampVoltage = 5;
emit dataChanged(createIndex(index,0), createIndex(index,0), {0,1,2} );
}
void DeviceModel::addDevice(const Device &Device)
{
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_Devices << Device;
endInsertRows();
}
int DeviceModel::rowCount(const QModelIndex & parent) const {
Q_UNUSED(parent);
return m_Devices.count();
}
QVariant DeviceModel::data(const QModelIndex & index, int role) const {
if (index.row() < 0 || index.row() >= m_Devices.count())
return QVariant();
const Device &Device = m_Devices[index.row()];
if (role == NodeIdRole)
return Device.nodeId();
else if (role == TypeRole)
return Device.type();
else if (role == LampVoltageRole)
return Device.lampVoltage();
return QVariant();
}
//![0]
QHash<int, QByteArray> DeviceModel::roleNames() const {
QHash<int, QByteArray> roles;
roles[NodeIdRole] = "nodeId";
roles[TypeRole] = "type";
roles[LampVoltageRole] = "lampVoltage";
return roles;
}
main.qml
ListView {
width: 200; height: 250
spacing: 10
model: myModel
delegate:
Text { text: "Animal: " + type + ", " + lampVoltage
MouseArea {
anchors.fill: parent
onClicked: {
console.log("egwegweg");
myModel.callFromQml(index);
//lampVoltage = 10;
// myModel.setData(index , 10 , 2);
}
}
}
}
main.cpp
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
DeviceModel model;
model.addDevice(Device(1, "Medium" , 200));
model.addDevice(Device(1, "Medium" , 200));
model.addDevice(Device(1, "Medium" , 200));
QQmlContext *ctxt = engine.rootContext();
ctxt->setContextProperty("myModel", &model);
engine.load(QUrl(QLatin1String("qrc:/main.qml")));
model.addDevice(Device(1, "Medium" , 200));
model.addDevice(Device(1, "Medium" , 200));
model.addDevice(Device(1, "Medium" , 200));
return app.exec();
i want modify my item values from Qml
i wrote a slot named callFromQml and pass index of item from qml to c++ code and want update the values from it
but can not do it
i don not know emit signal works or not and do not know pass index to it correctly or not and don not
Thanks for #MarkCh for pointing out, that you have not reimplemented the setData()-method.
The signature is:
bool QAbstractItemModel::setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole)
It returns true if some data was set successfully, and false if not.
Further, uppon success, before returning, it is necessary to emit dataChanged(...) so any views will be aware of the change.
Let's do it:
Add the appropriate declaration to the header file
Add the implementation to the .cpp-file. This might look like this:
bool QAbstractItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (index.row() < 0 || index.row() >= m_Devices.count())
return false;
const Device &Device = m_Devices[index.row()];
if (role == NodeIdRole) {
Device.m_nodeId = value.toInt();
emit dataChanged(index, index);
return true;
}
else if (role == TypeRole) {
Device.m_type = value.toString();
emit dataChanged(index, index);
return true;
}
else if (role == LampVoltageRole) {
Device.m_lampVoltage = value.toInt();
emit dataChanged(index, index);
return true;
}
return false;
}
Make DeviceModel a friend of Device or change the access of the private fields to usage of getters. As you like.
Now you should be able to set the roles in the delegate as if they were properties... Like:
onClicked: model.nodeId = 100;
The code above is not tested, but should include the most relevant details.

base class 'QAbstractListModel' has private copy constructor

I have a QT QML project. (still very small)
I started by binding a listview on my UScenario model, by subclassing QAbstractListModel and it worked fined.
Now, each UScenario has a list of UTask, which also have a list of UCondition (so, Utask also subclasses QAbstractListModel). But then, QT Creator gives me an error:
Core/Tasks/utask.h:6: erreur : base class 'QAbstractListModel' has private copy constructor
class UTask: public QAbstractListModel
^
So I'm not sure where is my problem. I tried reading the doc about QAbstractListModel vs QAbstractItemModel, but I have no clue.
I also tried to see if I ever constructed a UTask in a wrong way; I think not.
// USCENARIO.h
#ifndef USCENARIO_H
#define USCENARIO_H
#include <QAbstractListModel>
#include "../Tasks/utask.h"
class UScenario : public QAbstractListModel
{
Q_OBJECT
public slots:
void cppSlot() { // Used to test the insertion from UI
this->addTask(UTask());
}
public:
enum TaskRoles {
IdRole = Qt::UserRole + 1
};
UScenario(QObject *parent = 0);
private:
QList<UTask> m_tasks;
public:
void addTask(const UTask &task);
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
virtual QVariant data(const QModelIndex &index, int role) const;
virtual QHash<int, QByteArray> roleNames() const;
};
#endif // USCENARIO_H
// USCENARIO.CPP
#include "uscenario.h"
UScenario::UScenario(QObject *parent)
: QAbstractListModel(parent)
{
}
void UScenario::addTask(const UTask &task)
{
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_tasks.append(task);
endInsertRows();
}
int UScenario::rowCount(const QModelIndex & parent) const {
return m_tasks.count();
}
QVariant UScenario::data(const QModelIndex & index, int role) const {
if (index.row() < 0 || index.row() >= m_tasks.count())
return QVariant();
const UTask &task = m_tasks[index.row()];
if (role == IdRole)
return task.id();
return QVariant();
}
QHash<int, QByteArray> UScenario::roleNames() const {
QHash<int, QByteArray> roles;
roles[IdRole] = "id";
return roles;
}
// UTASK.H
#ifndef UTASK_H
#define UTASK_H
#include <QAbstractListModel>
#include "../Conditions/ucondition.h"
class UTask: public QAbstractListModel
{
Q_OBJECT
public:
enum TaskRoles {
typeRole = Qt::UserRole + 1
};
UTask(QObject *parent = 0);//:m_id(0){}
int id() const{return m_id;}
private:
int m_id;
QList<UCondition> m_conditions;
// QAbstractItemModel interface
public:
void addCondition(const UCondition &cond);
virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
virtual QVariant data(const QModelIndex &index, int role) const;
virtual QHash<int, QByteArray> roleNames() const;
};
#endif // UTASK_H
// UTASK.cpp
#include "utask.h"
UTask::UTask(QObject *parent):
QAbstractListModel(parent), m_id(0)
{
}
void UTask::addCondition(const UCondition &cond)
{
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_conditions.append(cond);
endInsertRows();
}
int UTask::rowCount(const QModelIndex &parent) const
{
return m_conditions.count();
}
QVariant UTask::data(const QModelIndex &index, int role) const
{
if (index.row() < 0 || index.row() >= m_conditions.count())
return QVariant();
const UCondition &cond = m_conditions[index.row()];
if (role == typeRole)
return cond.type();
return QVariant();
}
QHash<int, QByteArray> UTask::roleNames() const
{
QHash<int, QByteArray> roles;
roles[typeRole] = "type";
return roles;
}
// MAIN
#include <QtGui/QGuiApplication>
#include "qtquick2applicationviewer.h"
#include <qqmlengine.h>
#include <qqmlcontext.h>
#include <qqml.h>
#include <QtQuick/qquickitem.h>
#include <QtQuick/qquickview.h>
#include "../uCtrlCore/Scenario/uscenario.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
UScenario scenarioModel;
scenarioModel.addTask(UTask());
scenarioModel.addTask(UTask());
scenarioModel.addTask(UTask());
QtQuick2ApplicationViewer viewer;
QQmlContext *ctxt = viewer.rootContext();
ctxt->setContextProperty("myScenarioModel", &scenarioModel);
viewer.setMainQmlFile(QStringLiteral("qml/uCtrlDesktopQml/main.qml"));
QObject *item = viewer.rootObject()->findChild<QObject*>("btn");
QObject::connect(item, SIGNAL(qmlSignal()), &scenarioModel, SLOT(cppSlot()));
viewer.showExpanded();
return app.exec();
}
There problem is with how you're storing the UTask objects in your UScenario class
QList<UTask> m_tasks
In simple terms when you call m_tasks.append it is attempting to allocate a new UTask object in the QList by copying the source UTask object via the default copy constructor. In the case of QAbstractListModel it is private. This is why you're at getting the error.
A simply solution is to change the storage type to a list of UTask pointers, QList< UTask* > along with the supporting code to properly release the memory when your UScenario object is destroyed.
For example here are some but not all of the changes but should point you in the right direction. Just make sure to change m_tasks to QList< UTask* > first:
int main(int argc, char *argv[])
{
...
UScenario scenarioModel;
scenarioModel.addTask( new UTask() );
scenarioModel.addTask( new UTask() );
scenarioModel.addTask( new UTask() );
...
return app.exec();
}
void UScenario::cppSlot()
{
// Used to test the insertion from UI
this->addTask( new UTask() );
}
// Change the signature to take a pointer
void UScenario::addTask( UTask* task )
{
beginInsertRows(QModelIndex(), rowCount(), rowCount());
m_tasks.append(task);
endInsertRows();
}
// Make sure you define a destructor for UScenario
UScenario::~UScenario()
{
QList< UTask* >::iterator task = m_tasks.begin();
while( m_tasks.end() != task )
{
// Release the memory associated with the task.
delete (*task);
++task;
}
m_tasks.clear();
}

Cannot refresh QT's view while changing model

I am learning how to integrate qml with c++.
I've implemented a custom model class StringListModel, which inherits QAbstratListModel.
And, I have a main.qml to use StringListModel.
QML view can show initial values correctly.
I have another thread to change model periodically.
I do use beginResetModel() and endResetModel() to indicate model changed.
However, while the model keeps been changed, the view didn't update.
Here is my source code.
Please teach me what went wrong.
THANKS!
=== main.qml ===
Rectangle {
width: 360
height: 360
Grid {
id: gridview
columns: 2
spacing: 20
Repeater {
id: repeater
model: StringListModel {
id:myclass
}
delegate: Text {
text: model.title
}
}
}
=== custom class.h ===
class StringListModel : public QAbstractListModel{
Q_OBJECT
public:
StringListModel(QObject *parent = 0);
int rowCount(const QModelIndex &parent = QModelIndex()) const;
QVariant data(const QModelIndex &index, int role) const;
QHash<int, QByteArray> roleNames() const;
void newItem();
private:
QStringList stringList;
};
class UpdateThread : public QThread {
Q_OBJECT
StringListModel *mMyClass;
public:
UpdateThread(StringListModel * myClass);
protected:
void run();
};
=== custom class.cpp ===
StringListModel::StringListModel(QObject *parent) : QAbstractListModel(parent)
{
stringList << "one" << "two" << "three";
QThread *thread = new UpdateThread(this);
thread->start();
}
int StringListModel::rowCount(const QModelIndex &parent) const
{
return stringList.count();
}
QVariant StringListModel::data(const QModelIndex &index, int role) const
{
if (!index.isValid())
return QVariant();
if (index.row() >= stringList.size())
return QVariant();
if (role == Qt::UserRole + 1)
return stringList.at(index.row());
else
return QVariant();
}
QHash<int, QByteArray> StringListModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[Qt::UserRole + 1] = "title";
return roles;
}
void StringListModel::newItem()
{
qDebug() << "size: " << stringList.size();
beginResetModel();
stringList << "new";
endResetModel();
}
UpdateThread::UpdateThread(StringListModel * myClass)
{
mMyClass = myClass;
}
void UpdateThread::run()
{
while (true) {
mMyClass->newItem();
msleep(1000);
}
}
You're dutifully ignoring the matters of synchronizing access to the model. When you have any object that's accessed from more than one thread (even something as "simple" as a raw pointer), you must deal with the ramifications of such access.
I suggest you don't mess with threads unless you have measurements showing that you'll benefit.

Same Model Proxy View connection but doesn't work in second project

this works:
/*Just copy and paste*/
#include <QApplication>
#include <QtGui>
#include <QDebug>
#include <QAbstractProxyModel>
class File_List_Proxy : public QAbstractProxyModel
{
public:
virtual QModelIndex mapFromSource ( const QModelIndex & sourceIndex ) const
{
return sourceModel()->index(sourceIndex.row(),sourceIndex.column());
}
virtual QModelIndex mapToSource ( const QModelIndex & proxyIndex ) const
{
return sourceModel()->index(proxyIndex.row(),proxyIndex.column());
}
virtual QModelIndex index(int row, int column, const QModelIndex&) const
{
return createIndex(row,column);
}
virtual QModelIndex parent(const QModelIndex&) const
{
return QModelIndex();
}
virtual int rowCount(const QModelIndex&) const
{
return sourceModel()->rowCount();
}
virtual int columnCount(const QModelIndex&) const
{
return sourceModel()->columnCount();
}
};
class File_List_Model : public QAbstractItemModel
{
private:
QStringList data_;
public:
File_List_Model(/*const QStringList& value*/)//:QStringListModel(value)
{
}
QVariant data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole){
/*QVariant t = data_.at(index.row());
qDebug() << "index.row(): " << index.row();
qDebug() << "data_.at(index.row()): " << data_.at(index.row());*/
return data_.at(index.row());
}
else
{
return QVariant();
}
}
bool set_entries(const QStringList& entries)
{
beginInsertRows(createIndex(0,0),0,entries.count());
data_ = entries;
endInsertRows();
emit dataChanged(createIndex(0,0),createIndex(0,entries.count()));
return true;
}
bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::DisplayRole)
{
switch(role)
{
case Qt::DisplayRole:
data_ = value.toStringList();
emit dataChanged(index,index);
return true;
}
return false;
}
virtual QModelIndex index(int row, int column, const QModelIndex&) const
{
return createIndex(row,column);
}
virtual QModelIndex parent(const QModelIndex&) const
{
return QModelIndex();
}
virtual int rowCount(const QModelIndex&) const
{
return data_.size();
}
virtual int columnCount(const QModelIndex&) const
{
return 1;
}
};
int main(int argc,char** argv)
{
QApplication app(argc,argv);
QDir dir(QDesktopServices::storageLocation(QDesktopServices::HomeLocation));
File_List_Model* model = new File_List_Model;//(dir.entryList());
bool t = model->set_entries(dir.entryList());
File_List_Proxy* proxy = new File_List_Proxy;
proxy->setSourceModel(model);
QListView* view = new QListView;
view->setModel(proxy);
//new ModelTest(model);
view->show();
return app.exec();
}
/*End of copy*/
This on the contrary from a different project where File_List_Model and File_List_Proxy ARE COPIED AND NOT CHANGED from the code above doesn't work:
Line_Counter::Line_Counter(QWidget *parent) :
QDialog(parent), model_(new File_List_Model),
proxy_model_(new File_List_Proxy)
{
setupUi(this);
setup_mvc_();
QDir dir(QDesktopServices::storageLocation(QDesktopServices::HomeLocation));
File_List_Model* model = new File_List_Model;//(dir.entryList());
bool t = model->set_entries(dir.entryList());
}
void Line_Counter::setup_mvc_()
{
proxy_model_->setSourceModel(model_);
listView->setModel(proxy_model_);
}
//Line counter
class Line_Counter : public QDialog, private Ui::Line_Counter
{
Q_OBJECT
private:
File_List_Model* model_;
//QStringListModel* model_;
File_List_Proxy* proxy_model_;
};
What's going on here?!
You call the setup_mvc_ before the model creation. The model_ in this case it a default constructed model where the set_entries has not been called. On the other hand you call the set_entries on the model which you do not set to a view.
This will work:
Line_Counter::Line_Counter(QWidget *parent) :
QDialog(parent), model_(new File_List_Model),
proxy_model_(new File_List_Proxy)
{
setupUi(this);
QDir dir(QDesktopServices::storageLocation(QDesktopServices::HomeLocation));
bool t = model_->set_entries(dir.entryList());
setup_mvc_();
}

Resources