qt - C++/QML: ListView is not updated on dataChanged signal from QAbstractListModel -
i trying write qml gui large dynamic c/fortran simulation. data want display stored in fortran common blocks , updated on fixed time steps. problem qml listview not refresh when datachanged signal emitted after each time step, although signal received gui (test in code below).
i missing out obvious because when flick listview down , again, displayed data updated , correct (i guess because qml engine re-renders elements when "out of sight" , in again). thing not work listview gets updated every time datachanged signal received , not when re-rendered. below more detailed description of approach , relevant code parts.
each simulation entity has several attributes (alive, position...), decided create listmodel containing dataobject each entity. corresponding header file (the actual simulation data declared extern structs in "interface.h", can access via pointer):
"acdata.h"
#include <qtcore> #include <qobject> #include <qtgui> extern "c" { #include "interface.h" } class acdataobject : public qobject { q_object public: explicit acdataobject(int id_, int *pac_live, double *pac_pos_x, qobject *parent = 0) : qobject(parent) { entity_id = id_; ac_live = pac_live; ac_pos_x = pac_pos_x; } int entity_id; int *ac_live; double *ac_pos_x; }; class acdatamodel : public qabstractlistmodel { q_object public: enum rolenames { idrole = qt::userrole, liverole = qt::userrole + 1, posxrole = qt::userrole + 2 }; explicit acdatamodel(qobject *parent = 0); virtual int rowcount(const qmodelindex &parent) const; virtual qvariant data(const qmodelindex &index, int role) const; q_invokable qt::itemflags flags(const qmodelindex &index) const q_decl_override; void do_update(); protected: virtual qhash<int, qbytearray> rolenames() const; private: qlist<acdataobject*> data_list; qhash<int, qbytearray> m_rolenames; qmodelindex start_index; qmodelindex end_index; signals: void datachanged(const qmodelindex &start_index, const qmodelindex &end_index); };
like header, .cpp file adapted can find in qt5 cadaques book here, except constructor iterates on simulation entities set pointers. additionally, there do_update function emits datachanged signal whole list.
"acdata.cpp"
#include "acdata.h" acdatamodel::acdatamodel(qobject *parent) : qabstractlistmodel(parent) { m_rolenames[idrole] = "entity_id"; m_rolenames[liverole] = "ac_live"; m_rolenames[posxrole] = "ac_pos_x"; (int = 0; < max_entities; i++) // max_entities defined in interface.h { acdataobject *data_object = new acdataobject( i, &fdata_ac_.ac_live[i], // fdata_ac_ c struct/fortran common block defined in interface.h &fdata_ac_.ac_pos_x[i] ); data_list.append(data_object); } } int acdatamodel::rowcount(const qmodelindex &parent) const { q_unused(parent); return data_list.count(); } qvariant acdatamodel::data(const qmodelindex &index, int role) const { int row = index.row(); if(row < 0 || row >= data_list.count()) { return qvariant(); } const acdataobject *data_object = data_list.at(row); switch(role) { case idrole: return data_object->entity_id; case liverole: return *(data_object->ac_live); case posxrole: return *(data_object->ac_pos_x); } return qvariant(); } qhash<int, qbytearray> acdatamodel::rolenames() const { return m_rolenames; } void acdatamodel::do_update() { start_index = createindex(0, 0); end_index = createindex((data_list.count() - 1), 0); datachanged(start_index, end_index); } qt::itemflags acdatamodel::flags(const qmodelindex &index) const { if (!index.isvalid()) {return 0;} return qt::itemiseditable | qabstractitemmodel::flags(index); }
when simulation running, do_update() called every second. have created test gui listview , exposed model with:
excerpt "threadcontrol.cpp"
acdata = new acdatamodel(); viewer = new qtquick2applicationviewer(); viewer->rootcontext()->setcontextproperty("acdata", acdata); viewer->setmainqmlfile(qstringliteral("../lib/qml_gui/main.qml")); viewer->showexpanded();
(this code part of larger file controls different threads. quite sure rest not relevant actual problem , question getting long...)
so there main.qml. contains list max_entities elements , each elements holds text fields display data. have added connections element check if datachanged signal received gui.
"main.qml"
listview { id: listviewer model: acdata delegate: rectangle { /* ... formatting stuff height etc ... */ row { anchors.fill: parent text { /* ... formatting stuff ... */ text: model.entity_id } text { /* ... formatting stuff ... */ text: model.ac_live } text { /* ... formatting stuff ... */ text: model.ac_pos_x } } } connections { target: listviewer.model // edit: drew wrong conclusions here, see text below! ondatachanged: { console.log("datachanged received") } } }
when running simulation, "datachanged received" message printed every second.
edit: connecting listmodel , not listview here, although listview has receive datachanged signal. console log not work when connecting listviewer, missing connection between listview , datachanged signal. however, think should work automatically when implementing datachanged signal?
additional information: have found similar problem here qt map , seemed bug fixed in qt 5.6. however, running qmake qt 5.7 did not fix problem.
you mustn't declare datachanged()
signal in class, because want emit signal abstractitemmodel::datachanged()
. if re-declare add comleptely new , different signal not connected anywhere. if remove declaration in acdata.h should work fine.
Comments
Post a Comment