QML component isn't displayed if it was created programmatically from C++ - c++

My goal is to create a custom Component (lets call it ComponentLoader) which can instantiate another component (lets call it DelegateComponent) via delegate.
The problem is that the instance of DelegateComponent isn't displayed after is was created (white screen). Note: tst_component is loaded message IS present which means that DelegateComponent instance was actually created.
Here is a minimal example:
main.qml
ApplicationWindow {
id: mainWindow
width: 640
height: 480
visible: true
Component {
id: tst_component
Rectangle {
anchors.fill: parent
Component.onCompleted: {
console.debug("tst_component is loaded");
}
Label {
text: "hello world"
anchors.centerIn: parent
}
}
}
// doesn't work
ComponentLoader {
anchors.fill: parent
delegate: tst_component
}
// works
// Loader {
// anchors.fill: parent
// sourceComponent: tst_component
// }
}
componentloader.h + componentloader.cpp
#pragma once
#include <QQuickItem>
class ComponentLoader : public QQuickItem
{
Q_OBJECT
Q_PROPERTY(QQmlComponent* delegate READ delegate WRITE setDelegate NOTIFY delegateChanged)
public:
QQmlComponent* delegate() const;
void setDelegate(QQmlComponent*);
signals:
void delegateChanged();
private:
void generate();
protected:
void componentComplete() override;
private:
QQmlComponent* mDelegate = nullptr;
};
// componentloader.cpp
#include "componentloader.h"
#include <QtWidgets/QtWidgets>
#include <QtQmlModels/QtQmlModels>
#include <QQuickWindow>
QQmlComponent* ComponentLoader::delegate() const
{
return mDelegate;
}
void ComponentLoader::setDelegate(QQmlComponent* delegate)
{
if (delegate != mDelegate)
{
mDelegate = delegate;
emit delegateChanged();
}
}
void ComponentLoader::componentComplete()
{
QQuickItem::componentComplete();
generate();
}
void ComponentLoader::generate()
{
QQmlEngine* engine = qmlEngine(this);
QQmlContext* root_ctx = engine->rootContext();
QQmlContext* ctx = new QQmlContext(root_ctx);
QObject* item = mDelegate->create(ctx);
QQuickItem* quickItem = qobject_cast<QQuickItem*>(item);
QQuickItem* quickParent = qobject_cast<QQuickItem*>(parent());
quickItem->setParent(quickParent);
quickItem->setParentItem(quickParent);
}

Your quickParent pointer is taking the QObject parent() value instead of the QQuickItem parentItem() value.
Simply changing it to this worked for me when I tried your code:
QQuickItem* quickParent = qobject_cast<QQuickItem*>(parentItem());
I also don't think you need to call setParent() at all. Just setParentItem().

Related

How to use C++ struct array for QML ComboBox?

I've got a struct with two fields, for example:
struct testStruct
{
Q_GADGET
Q_PROPERTY(QString text MEMBER m_text);
Q_PROPERTY(QString value MEMBER m_value);
public:
QString m_text;
QString m_value;
};
There is a QList<testStruct> m_testStructs member of my "AppEngine" class exposed to QML via
Q_PROPERTY(QList<testStruct> testStructs READ testStructs NOTIFY testStructsChanged).
It is filled like that:
testStruct newStruct1, newStruct2;
newStruct1.m_text = "text1";
newStruct1.m_value = "value1";
newStruct2.m_text = "text2";
newStruct2.m_value = "value2";
m_testStructs << newStruct1 << newStruct2;
So I want to see "text" members in ComboBox list and use "value" members in further operations.
In fact QML ComboBox popup shows me the list of objects names when I set ComboBox's "textRole" property to "text" and "valueRole" to "value", but it does nothing for "currentText" or "currentValue" properties when I click the item, only "currentIndex" changes. Also "displayText" remains blank.
This is what I get in console when clicking those items:
qml: currentIndex: 0; currentText: ; currentValue: undefined
qml: currentIndex: 1; currentText: ; currentValue: undefined
So I see that ComboBox gets members of struct, but doesn't want to work with them. What should I do to make "currentText" and "currentValue" members of ComboBox work as they should?
Here are all the needed files:
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include "appengine.h"
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
const QUrl url(u"qrc:/qml_testComboBoxStruct/main.qml"_qs);
QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
&app, [url](QObject *obj, const QUrl &objUrl) {
if (!obj && url == objUrl)
QCoreApplication::exit(-1);
}, Qt::QueuedConnection);
//exposing AppEngine class to QML
AppEngine appEngineObj;
QQmlContext *context = engine.rootContext();
context->setContextProperty("AppEngine", &appEngineObj);
engine.load(url);
return app.exec();
}
my custom class header AppEngine.h
#ifndef APPENGINE_H
#define APPENGINE_H
#include <QObject>
#include <QDebug>
struct testStruct
{
Q_GADGET
Q_PROPERTY(QString text MEMBER m_text);
Q_PROPERTY(QString value MEMBER m_value);
public:
QString m_text;
QString m_value;
};
Q_DECLARE_METATYPE(testStruct)
class AppEngine : public QObject
{
Q_OBJECT
Q_PROPERTY(QList<testStruct> testStructs READ testStructs NOTIFY testStructsChanged);
public:
explicit AppEngine(QObject *parent = nullptr);
QList<testStruct> testStructs();
private:
QList<testStruct> m_testStructs;
signals:
void testStructsChanged();
};
#endif // APPENGINE_H
my custom class cpp file AppEngine.cpp
#include "appengine.h"
AppEngine::AppEngine(QObject *parent)
: QObject{parent}
{
testStruct newStruct1, newStruct2;
newStruct1.m_text = "text1";
newStruct1.m_value = "value1";
newStruct2.m_text = "text2";
newStruct2.m_value = "value2";
m_testStructs << newStruct1 << newStruct2;
qDebug() << "m_testStructs.length():" << m_testStructs.length();
}
QList<testStruct> AppEngine::testStructs()
{
qDebug() << "testStructs()";
return m_testStructs;
}
main.qml
import QtQuick
import QtQuick.Controls
Window {
width: 640
height: 480
visible: true
title: qsTr("C++ struct to QML ComboBox")
ComboBox
{
anchors.centerIn: parent
width: 180
height: 30
id: comboBoxID
textRole: "text"
valueRole: "value"
model: AppEngine.testStructs
onActivated:
{
console.log('currentIndex:', currentIndex, '; currentText:', currentText, ';currentValue:', currentValue);
}
}
}
As I checked in the main.qml model property cant find and understand as you show it is undefined.
qml: currentIndex: 0; currentText: ; currentValue: undefined
qml: currentIndex: 1; currentText: ; currentValue: undefined
from ListView::model property
The model provides the set of data that is used to create the items in
the view. Models can be created directly in QML using ListModel,
ObjectModel, or provided by C++ model classes. If a C++ model class is
used, it must be a subclass of QAbstractItemModel or a simple list.
For example, you can have this :
import QtQuick
import QtQuick.Controls
Window {
width: 640
height: 480
visible: true
title: qsTr("C++ struct to QML ComboBox")
ComboBox
{
id: comboBoxID
anchors.centerIn: parent
width: 180
height: 30
textRole: "text"
valueRole: "value"
model: ListModel {
id : model
ListElement { text: "text1" ; value : "value1" }
ListElement { text: "text2" ; value : "value2" }
ListElement { text: "text3" ; value : "value3" }
ListElement { text: "text4" ; value : "value4" }
}
onActivated:
{
console.log('currentIndex:', currentIndex, '; currentText:', currentText, '; currentValue:', currentValue);
}
}
}
Because you use QML ListModel if you want to define your model from C++ it must be a subclass of QAbstractItemModel or a simple list.
updated :
you need to use QStandardItemModel which inherits from QAbstractItemModel you cant inherit from the abstract interface because of that I use QStandardItemModel
in appengine.h:
#ifndef APPENGINE_H
#define APPENGINE_H
#include <QObject>
#include <QDebug>
#include <QStandardItemModel>
struct testStruct: public QStandardItemModel
{
Q_OBJECT
Q_PROPERTY(QString text MEMBER m_text);
Q_PROPERTY(QString value MEMBER m_value);
public:
QString m_text;
QString m_value;
};
Q_DECLARE_METATYPE(testStruct)
class AppEngine : public QObject
{
Q_OBJECT
Q_PROPERTY(QList<testStruct *> testStructs READ testStructs NOTIFY testStructsChanged);
public:
explicit AppEngine(QObject *parent = nullptr);
QList<testStruct *> testStructs();
private:
QList<testStruct *> m_testStructs;
signals:
void testStructsChanged();
};
#endif // APPENGINE_H
In appengine.cpp
#include "appengine.h"
AppEngine::AppEngine(QObject *parent)
: QObject{parent}
{
testStruct *newStruct1 = new testStruct;
testStruct *newStruct2 = new testStruct;
newStruct1->m_text = "text1";
newStruct1->m_value = "value1";
newStruct2->m_text = "text2";
newStruct2->m_value = "value2";
m_testStructs << newStruct1 << newStruct2;
qDebug() << "m_testStructs.length():" << m_testStructs.length();
}
QList<testStruct *> AppEngine::testStructs()
{
qDebug() << "testStructs()";
return m_testStructs;
}

Right QML <-> C++ declarative approach

I have some data structure updated in c++ layer. I have to display it in qml and save changes from qml layer to c++ structures. I hope there is a declarative approach to do it but I in desperate to find it.
Here is the part of code:
C++ header:
#ifndef NODEINFO_H
#define NODEINFO_H
#include <QObject>
#include <QString>
class NodeInfo : public QObject {
Q_OBJECT
Q_PROPERTY(QString label READ label WRITE setLabel NOTIFY labelChanged)
public:
NodeInfo(QObject *parent = 0);
virtual ~NodeInfo() {}
const QString& label() const;
void setLabel(const QString& val);
signals:
void labelChanged();
private:
QString d_label;
};
#endif // NODEINFO_H
C++ body:
#include "nodeinfo.h"
#include <QDebug>
NodeInfo::NodeInfo(QObject *parent) : QObject(parent), d_label("Test string") {
}
const QString &NodeInfo::label() const {
qDebug() << "NodeInfo::label: getter";
return d_label;
}
void NodeInfo::setLabel(const QString &val) {
qDebug() << "NodeInfo::label: setter - " << val;
d_label = val;
emit labelChanged();
}
main.cpp
#include <QGuiApplication>
#include <QDebug>
#include <QQmlContext>
#include <QQuickView>
#include <QQmlApplicationEngine>
#include "nodeinfo.h"
int main(int argc, char *argv[]) {
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
// qmlRegisterType<NodeInfo>("NodeInfo", 1, 0, "NodeInfo");
NodeInfo nodeDescr;
QQmlApplicationEngine engine;
engine.rootContext()->setContextProperty("nodeData", &nodeDescr);
const QUrl url(QStringLiteral("qrc:/main.qml"));
engine.load(url);
QObject *root = engine.rootObjects().value(0);
if (QWindow *window = qobject_cast<QWindow *>(root))
window->show();
else
return -1;
return app.exec();
}
Qml code:
import QtQuick 2.15
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
ApplicationWindow {
id: root
width: 360
height: 520
visible: true
// property alias a_label: nodeData.label
Column {
anchors.fill: parent
TextInput {
id: simpleTxt
text: nodeData.label
}
Text {
id: txt
text: nodeData.label
}
Button {
text: "writeProp"
onClicked: nodeData.label = simpleTxt.text
}
// Binding {
// target: nodeData
// property: "label"
// value: simpleTxt.text
// }
}
}
So when I'm editing text in TextInput it should automatically set property in c++ code but it do not. Only if I press button.
There is the Binding way as you see in comments and it works but I it's not a true way I hope.
Let's imagine if I have 15-30 or more data fields in my c++ structure and it's full rubbish if I must do 30 Bindings such way or if I need to write signal/slot on each data field and connect them.
But what is right way?
Any ideas appreciated
A simpler solution is to assign the signal associated to the property text:
Text {
id: txt
text: nodeData.label
onTextChanged: {
if(nodeData.label != simpleTxt.text)
nodeData.label = simpleTxt.text
}
}
text: nodeData.label sets binding nodeData.label --> text (one direction). I.e. text is updated whenever nodeData.label is changed. When the user types some text in the field, this binding is destroyed.
So if you want to update nodeData.label when the user changes text, you need to use onTextChaged event.
Text {
onTextChanged: nodeData.label = text
}
One more note: you need to check if the property is really changed before emitting the appropriate changed signal. So the code should be something like this:
void NodeInfo::setLabel(const QString &val) {
qDebug() << "NodeInfo::label: setter - " << val;
if (d_label != val)
{
d_label = val;
emit labelChanged();
}
}
This will prevent your code from endless binding loops.

C++ does not find QML StackView

I need to push a qml page to stackview from other qml page.
So i am using c++-qml interacting for this problem.
my c++ code finds page item, but does not find stackView.
main.cpp:
int main(int argc, char *argv[])
{
...
QQmlEngine engine;
QQmlComponent component(&engine, QUrl("qrc:/qml/main.qml"));
QObject* object = component.create();
Settings::defineObject(object);
return app.exec();
}
settings.h:
class Settings : public QObject
{
Q_OBJECT
private:
static QObject* object;
public:
...
Q_INVOKABLE void push(QString fileName);
static void defineObject(QObject* obj);
};
settings.cpp:
QObject* Settings::object = nullptr;
...
void Settings::push(QString fileName)
{
if (Settings::object == nullptr) QCoreApplication::exit(-3);
QObject* page = Settings::object->findChild<QObject*>("page");
if (!page) QCoreApplication::exit(-4);
QObject* stackView = page->findChild<QObject*>("stackView");
if (!stackView) QCoreApplication::exit(-5);
QMetaObject::invokeMethod(stackView, "push", Q_ARG(QString, fileName));
}
void Settings::defineObject(QObject* obj)
{
object = obj;
}
main.qml:
ApplicationWindow {
...
Page {
id: page
...
StackView {
id: stackView
initialItem: "Home.qml"
anchors.fill: parent
}
}
}
My program always exits -5 code.

qmlRegisterType in main behave wierd

I implemented a model in c++ and want to assign to Qml, but the error message showed that:
Unable to assign a function to a property of any type other than var.
What might be the problem with my code, thanks!
.qml
ListView{
anchors.fill: parent
model:MyModel{
list:data
}
delegate: objRecursiveDelegate
}
main.cpp
qmlRegisterType<MyModel>("Model",1,0,"MyModel");
qmlRegisterUncreatableType<Data>("Model",1,0,"Data",QStringLiteral("Data should not be created in QML"));
Data data;
engine.rootContext()->setContextProperty(QStringLiteral("data"), &data);
MyModel.h(try to define using QAbstractListModel)
class Data;
class MyModel : public QAbstractListModel
{
Q_OBJECT
Q_PROPERTY(Data *list READ list WRITE setList)
public:
Data *list() const;
void setList(Data *list);
private:
Data* mList;
}
MyModel.cpp
Data *MyModel::list() const
{
return mList;
}
void MyModel::setList(Data *list)
{
beginResetModel();
if (mList)
mList->disconnect(this);
mList = list;
/..../
endResetModel();
}
data.h
class Data:public QObject
{
Q_OBJECT
public:
explicit Data(QObject *parent = nullptr);
/..../
private:
QVector<unit> menu;
};
The error is really simple, the data() method of QAbstractListModel, so if you use data inside MyModel it is interpreting that you want to use this method and not the data that you really want to pass, the solution is to change the name:
*.cpp
Data data;
engine.rootContext()->setContextProperty(QStringLiteral("info"), &data);
*.qml
ListView{
anchors.fill: parent
model:MyModel{
list: info
}
delegate: objRecursiveDelegate
}
Plus:
On the other hand you have another error, the Data items method must return menu:
QVector<unit> Data::items() const{
return menu;
}
On the other hand in your delegate you must access access to each role using the name if the model:
Component {
id: objRecursiveDelegate
Column {
Row {
//indent
Item {
height: 1
width: level * 40 // <--
}
Text {
text: name // <--
}
Button{
x:550
width:30
text: "-"
}
}
}
}
I have made other improvements to your code so you can find the complete code in the following link.

Qml TableView: crash while scrolling

My goal is to implement a sort of simulator, with high rate data updates.
The application is composed from the following parts:
A data model: it stores the data and it is used by a TableView as a model
A simulator: a thread which updates the whole data model every 250ms
A Qml view: contains a TableView to show the data
As soon as I start the application, I can see the data changing in the TableView, but there is a wierd crash if I try to scroll the TableView using the mouse wheel (keep scrolling for a while).
The only log I get is the following:
ASSERT failure in QList::at: "index out of range", file C:\work\build\qt5_workdir\w\s\qtbase\include/QtCore/../../src/corelib/tools/qlist.h, line 510
The more interesting thing is that I get this crash only in a Windows environment, while in a CentOs machine I do not get any error.
I tried here to extract the main part of my project and to generalize it as much as possibile. Find below the code, or if you prefer you can download the full project from this link
mydata.h
#ifndef MYDATA_H
#define MYDATA_H
#include <QObject>
class MyData : public QObject
{
Q_OBJECT
Q_PROPERTY(int first READ first WRITE setFirst NOTIFY firstChanged)
Q_PROPERTY(int second READ second WRITE setSecond NOTIFY secondChanged)
Q_PROPERTY(int third READ third WRITE setThird NOTIFY thirdChanged)
public:
explicit MyData(int first, int second, int third, QObject* parent=0);
int first()const {return m_first;}
int second()const {return m_second;}
int third()const {return m_third;}
void setFirst(int v){m_first=v;}
void setSecond(int v){m_second=v;}
void setThird(int v){m_third=v;}
signals:
void firstChanged();
void secondChanged();
void thirdChanged();
private:
int m_first;
int m_second;
int m_third;
};
#endif // MYDATA_H
mydata.cpp
#include "mydata.h"
MyData::MyData(int first, int second, int third, QObject* parent) : QObject(parent)
{
m_first=first;
m_second=second;
m_third=third;
}
datamodel.h
#ifndef DATAMODEL_H
#define DATAMODEL_H
#include <QAbstractListModel>
#include <QMutex>
#include "mydata.h"
class DataModel: public QAbstractListModel
{
Q_OBJECT
public:
enum DataModelRoles {
FirstRole = Qt::UserRole + 1,
SecondRole,
ThirdRole
};
//*****************************************/
//Singleton implementation:
static DataModel& getInstance()
{
static DataModel instance; // Guaranteed to be destroyed.
// Instantiated on first use.
return instance;
}
DataModel(DataModel const&) = delete;
void operator=(DataModel const&) = delete;
//*****************************************/
QList<MyData*>& getData(){return m_data;}
void addData(MyData* track);
int rowCount(const QModelIndex & parent = QModelIndex()) const;
QVariant data(const QModelIndex & index, int role = FirstRole) const;
protected:
QHash<int, QByteArray> roleNames() const;
private:
QMutex m_mutex;
QList<MyData*> m_data;
DataModel(QObject* parent=0);
};
#endif // DATAMODEL_H
datamodel.cpp
#include "DataModel.h"
#include "QDebug"
DataModel::DataModel(QObject* parent): QAbstractListModel(parent)
{
}
void DataModel::addData(MyData *track)
{
beginInsertRows(QModelIndex(),rowCount(),rowCount());
m_data<<track;
endInsertRows();
}
int DataModel::rowCount(const QModelIndex &parent) const
{
Q_UNUSED(parent)
return m_data.size();
}
QVariant DataModel::data(const QModelIndex &index, int role) const
{
MyData* data=m_data[index.row()];
switch (role) {
case FirstRole:
return data->first();
case SecondRole:
return data->second();
case ThirdRole:
return data->third();
default:
return QVariant();
}
}
QHash<int, QByteArray> DataModel::roleNames() const
{
QHash<int, QByteArray> roles;
roles[FirstRole] = "First";
roles[SecondRole] = "Second";
roles[ThirdRole] = "Third";
return roles;
}
simulator.h
#ifndef SIMULATOR_H
#define SIMULATOR_H
#include <QThread>
class Simulator: public QThread
{
Q_OBJECT
public:
Simulator(QObject* parent=0);
void run() Q_DECL_OVERRIDE;
private:
void createNewData();
void updateExistingData();
int randInt(int from, int to);
};
#endif // SIMULATOR_H
simulator.cpp
#include "simulator.h"
#include <math.h>
#include <mydata.h>
#include <datamodel.h>
Simulator::Simulator(QObject* parent) : QThread(parent)
{
createNewData();
}
void Simulator::run()
{
long updateRate=250;
while(true)
{
updateExistingData();
msleep(updateRate);
}
}
void Simulator::createNewData()
{
int numOfData=10000;
for(int i=0;i<numOfData;i++)
{
int first=i;
int second=randInt(0,1000);
int third=randInt(0,1000);
MyData* data=new MyData(first,second,third);
DataModel::getInstance().addData(data);
}
}
void Simulator::updateExistingData()
{
QList<MyData*> list=DataModel::getInstance().getData();
for(int i=0;i<list.size();i++)
{
MyData* curr=list.at(i);
curr->setSecond(curr->second()+1);
curr->setThird(curr->third()+2);
QModelIndex index=DataModel::getInstance().index(i,0, QModelIndex());
emit DataModel::getInstance().dataChanged(index,index);
}
}
int Simulator::randInt(int from, int to)
{
// Random number between from and to
return qrand() % ((to + 1) - from) + from;
}
main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "simulator.h"
#include "datamodel.h"
#include <QQmlContext>
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);
DataModel& model=DataModel::getInstance();
Simulator* s=new Simulator();
s->start();
QQmlApplicationEngine engine;
QQmlContext *ctxt = engine.rootContext();
ctxt->setContextProperty("myModel", &model);
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));
return app.exec();
}
main.qml
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
import QtQuick.Controls.Styles 1.4
Window {
visible: true
width: 800
height: 600
TableView {
id: tableView
width: parent.width
height: parent.height
frameVisible: true
model: myModel
sortIndicatorVisible: true
property string fontName: "Arial"
TableViewColumn {
id: firstColumn
title: "First"
role: "First"
movable: false
resizable: false
width: tableView.viewport.width/3
delegate: Text{
font.family: tableView.fontName
text: styleData.value
horizontalAlignment: TextInput.AlignHCenter
verticalAlignment: TextInput.AlignVCenter
}
}
TableViewColumn {
id: secondColumn
title: "Second"
role: "Second"
movable: false
resizable: false
width: tableView.viewport.width/3
delegate: Text{
font.family: tableView.fontName
text: styleData.value
horizontalAlignment: TextInput.AlignHCenter
verticalAlignment: TextInput.AlignVCenter
}
}
TableViewColumn {
id: thirdColumn
title: "Third"
role: "Third"
movable: false
resizable: false
width: tableView.viewport.width/3
delegate: Text{
font.family: tableView.fontName
text: styleData.value
horizontalAlignment: TextInput.AlignHCenter
verticalAlignment: TextInput.AlignVCenter
}
}
}
}
I am glad to share with you the solution to my own answers, hoping it could help someone who is getting the same error.
The key point of the problem is here:
void Simulator::updateExistingData()
{
QList<MyData*> list=DataModel::getInstance().getData();
for(int i=0;i<list.size();i++)
{
MyData* curr=list.at(i);
curr->setSecond(curr->second()+1);
curr->setThird(curr->third()+2);
QModelIndex index=DataModel::getInstance().index(i,0, QModelIndex());
emit DataModel::getInstance().dataChanged(index,index); //ERROR!
}
}
In fact I am emitting a signal on the DataModel in a thread that is not the Gui thread: this will fall into a concurrent access issue, between the gui thread (which is accessing the data to fill the TableView) and the updater thread (which is accessing the data to update the values).
The solution is to emit the dataChanged signal on the gui thread, and we can do that by using the Qt Signal/Slot mechanism.
Therefore:
In datamodel.h:
public slots:
void updateGui(int rowIndex);
In datamodel.cpp:
void DataModel::updateGui(int rowIndex)
{
QModelIndex qIndex=index(rowIndex,0, QModelIndex());
dataChanged(qIndex,qIndex);
}
In simulator.h:
signals:
void dataUpdated(int row);
In simulator.cpp:
Simulator::Simulator(QObject* parent) : QThread(parent)
{
createNewData();
connect(this,SIGNAL(dataUpdated(int)), &DataModel::getInstance(), SLOT(updateGui(int)));
}
...
void Simulator::updateExistingData()
{
QList<MyData*> list=DataModel::getInstance().getData();
for(int i=0;i<list.size();i++)
{
MyData* curr=list.at(i);
curr->setSecond(curr->second()+1);
curr->setThird(curr->third()+2);
QModelIndex index=DataModel::getInstance().index(i,0, QModelIndex());
emit dataUpdated(i);
}
}
Using the Signal/Slot approach, we are sure that the request will be handled in the receiver class by the thread who have created that class (the Gui thread), therefore the following dataChanged signal will be emitted by the proper thread.