View Full Version : Modify c++ model data from QML Repeater
laszlo.gosztola
9th February 2011, 09:49
Hi all!
I would like to create something similar to the corkboard qml example. On a screen I have some items, which I can move, resize, rotate, and I can store these properties.
I created a model inherited from QAbstractListModel on C++ side. It populates data well.
On the QML side I show it in a Repeater, like this:
Repeater {
id: myRepeater
model: dayScreenModel
DayScreenEntry {
x: position.x
y: position.y
text: title
}
position, title, size, rotation comes from the C++ model.
It works fine.
But how can I achieve modification of these data?
I found a way:
in the model, created a public slot:
void updateData(int index, QString role, QVariant value);
and, in the DayScreenEntry.qml I can call like this:
myRepeater.model.updateData(index, "title", "NewTitle")
I can refresh the data in code, and it populates also to the qml side, shows the changes.
But, I have some problems with it:
- it's not 'elegant' - Is it possible somehow to call the 'setData' function of the model?
- on QML side, i have to write the model name in the delegate - I can use it only for this model, have to know the model name.
Do You know any other way to get this stuff working?
wysota
9th February 2011, 19:05
Since the delegate is a component, it should be possible to have it contain an item that allows you to edit the content it displays (like the TextEdit element). If you bind the model's property to a property that is editable by the component, there is a good chance the change will be propagated to the model.
laszlo.gosztola
9th February 2011, 20:53
Hello!
Thank You for your reply. I want expect what you write. But I don't know, how...
I attach a simple example.
The interesting part is in the qml file's mousearea section. I can reach the index, and the title also... But I cannot change the title :(
Maybe only I forgot to set a flag or something like this.
I think, that 'setData' should be called somehow as when the data populates from the model to the view - it's achieved by the 'data' function.
5910
main.cpp
#include <QApplication>
#include <QMessageBox>
#include "mainwidget.h"
int main(int argc, char** argv)
{
QApplication a (argc, argv);
MainWidget* mainWidget=new MainWidget();
mainWidget->show();
int r=0;
try
{
r=a.exec();
}catch (...)
{
QMessageBox::critical(NULL, QObject::tr("Error"), QObject::tr("Critical error - Unhandled exception in the application!"));
r=-1;
}
delete mainWidget;
return r;
}
mainwidget.h
#ifndef MAINWIDGET_H
#define MAINWIDGET_H
#include <QtDeclarative/QDeclarativeView>
#include "dummymodel.h"
class MainWidget : public QDeclarativeView
{
Q_OBJECT;
public:
MainWidget(QWidget* parent=0);
~MainWidget();
public slots:
private:
QDeclarativeContext* m_context;
DummyModel model;
};
#endif // MAINWIDGET_H
mainwidget.cpp
#include "mainwidget.h"
#include <QtDeclarative>
#include <QDeclarativeContext>
MainWidget::MainWidget(QWidget* parent) : QDeclarativeView(parent)
{
setResizeMode(QDeclarativeView::SizeRootObjectToVi ew);
setMinimumSize(300,300);
m_context=rootContext();
m_context->setContextProperty("dummyModel", &model);
setSource(QUrl("qml/qmlModel/main.qml"));
}
MainWidget::~MainWidget()
{
}
dummymodel.h
#ifndef DUMMYMODEL_H
#define DUMMYMODEL_H
#include <QAbstractListModel>
#include <QStringList>
class DummyModel : public QAbstractListModel
{
Q_OBJECT
public:
enum DummyRoles {
TitleRole=Qt::UserRole+1
};
DummyModel(QObject* parent=NULL);
~DummyModel();
int rowCount(const QModelIndex &parent) const;
QVariant data(const QModelIndex &index, int role) const;
bool setData(const QModelIndex &index, const QVariant &value, int role);
private:
void fillData();
QStringList m_data;
};
#endif // DUMMYMODEL_H
dummymodel.cpp
#include "dummymodel.h"
#include <QDateTime>
DummyModel::DummyModel(QObject *parent) : QAbstractListModel(parent)
{
m_data.clear();
QHash<int, QByteArray> roles;
roles[TitleRole]="title";
setRoleNames(roles);
fillData();
}
DummyModel::~DummyModel()
{
}
int DummyModel::rowCount(const QModelIndex &parent) const
{
return m_data.count();
}
QVariant DummyModel::data(const QModelIndex &index, int role) const
{
qDebug("dummymodel::data");
qDebug("Role: %d", role);
if (!index.isValid()) return QVariant();
if ((index.row()<0) || (index.row()>=m_data.count())) return QVariant();
if (role==TitleRole)
return m_data.at(index.row());
return QVariant();
}
void DummyModel::fillData()
{
qsrand(QDateTime::currentMSecsSinceEpoch());
beginResetModel();
m_data.clear();
int num=1+qrand()%8;
for (int i=0; i<num; i++)
{
m_data.append(QString("DummyText%1").arg(i+1));
}
endResetModel();
}
bool DummyModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
qDebug("SetData called");
return true;
}
and the qml file:
main.qml
import QtQuick 1.0
Rectangle {
id: base
width: 500
height: 360
Repeater {
model: dummyModel
delegate: myDelegate
}
Component {
id: myDelegate
Rectangle {
x: 10
y: index*35+10
width: 200
height: 30
color: "yellow"
TextEdit {
text: title
font.pointSize: 18
}
MouseArea {
anchors.fill: parent
onClicked: {
console.log("Clicked index:",index);
title="test"
}
}
}
}
}
wysota
9th February 2011, 22:22
Try implementing flags() for your model and return ItemIsEditable.
laszlo.gosztola
9th February 2011, 23:12
Already tried.
Qt::ItemFlags DummyModel::flags(const QModelIndex &index) const
{
qDebug("DummyModel::Flags");
return Qt::ItemIsEditable;
}
But unfortunately it doesn't help, but even the function is not called. (No qDebug output)
wysota
9th February 2011, 23:24
You have to return other flags as well.Like ItemIsEnabled. Make sure the signature fits and verify using QListView that your model is editable.
laszlo.gosztola
10th February 2011, 09:47
It is a good idea to test also with a QListView...
I found that the behavior is a little different.
From QML the flags function never called. In the data function the role is just the roles I have defined with setRoleNames call.
If I use a form with QListView flags is called many times, and role is DisplayRole, and others, so I had to extend the model, to implement the displayrole also.
But from QML, the answer is always: Cannot assign to read-only property 'title'
Any other idea?
Maybe I should use the solution with calling the slots...
Matriarch
19th October 2011, 14:35
I am also trying to use QAbstractItemModel::setData from QML, but it is not possible. QML model-view-controller connection with C++ Qt is build-in hardcoded suck, thats all.
Powered by vBulletin® Version 4.2.5 Copyright © 2024 vBulletin Solutions Inc. All rights reserved.