QML ListView does not reflect updates from its C++ data model [Solved]
-
wrote on 20 Jan 2015, 16:23 last edited by
My model inherits QAbstractListModel, I have a method to clear all items in the list, which is triggered by a mouse press event from the QML file, I'm able to receive this event fine. While the C++ model does get cleared, the ListView does not seem to reflect that change on the UI.
Relevant snippet from the header file of my model.
my_data_model.h
@class MyDataModel : public QAbstractListModel
{
public:
MyDataModel();
int rowCount( const QModelIndex& ) const;
QVariant data( const QModelIndex& index, int role = Qt::DisplayRole ) const;
void clearMyData();
private:
QList< MyData > my_data;
};@my_data_model.cpp
@void MyDataModel::clearMyData()
{
my_data.clear();
}@The qml file's relevant code snippet. name and content are properties derived through the data model's template structure.
my_data.qml
@Rectangle {
id:listRectangle
width: 650; height: 250ListView { id:listView objectName: "listView" width: parent.width; height: parent.height anchors.centerIn: parent clip:true spacing: 5 model: myDataModel focus: false delegate: Rectangle { id: delegate objectName: name Text { id: titleText text: content } MouseArea { id:ma anchors.fill: parent onClicked: { listView.currentIndex = index; } } } }
}@
The qml is invoked like this:
model_usage_widget.cpp
@xView = new QDeclarativeView(this);
context = xView->engine()->rootContext();
MyDataModel myDataModel;
context->setContextProperty("myDataModel", &myDataModel);
xView->setSource(QUrl("qrc:/ui/qml/my_data_model.qml"));
xLayout = new QHBoxLayout(this);
xLayout->setMargin(0);
xLayout->addWidget(xView);
this->setLayout(xLayout);
this->show();@this is an object that inherits QWidget
I've included all relevant code above. I created my list with one item, and tried to clear it but the QML does not seem to update it's view. Do I have to add anything else?
-
wrote on 20 Jan 2015, 23:03 last edited by
Q_PROPERTY(QQuickItem *target READ target WRITE setTarget NOTIFY targetChanged)
Q_PROPERTY(int cursorPosition READ cursorPosition WRITE setCursorPosition NOTIFY cursorexample doc.
-
Hi,
my_data.clear() will just clear the list but you will the view to be notified about the changes. This can be done by wrapping it up in "beginResetModel":http://doc.qt.io/qt-5/qabstractitemmodel.html#beginResetModel and endResetModel:
@
beginResetModel();
my_data.clear();
endResetModel();
@ -
wrote on 21 Jan 2015, 15:22 last edited by
I just tried inserting that, and my Application Crashed as soon as that code was invoked. Narrowed it down to endResetModel() being the culprit.
-
wrote on 21 Jan 2015, 15:41 last edited by
This code works for me:
@ emit layoutAboutToBeChanged();
my_data.clear();
emit layoutChanged();@ -
wrote on 21 Jan 2015, 16:02 last edited by
So, with this the Application no longer crashes but my view still seems to hold the model item's in it's view but the I'm not able to scroll between the items.
[quote author="ondrejandrej" date="1421854871"]This code works for me:
@ emit layoutAboutToBeChanged();
my_data.clear();
emit layoutChanged();@[/quote]As an aside, it'd be nice to find a complete example of a c++ model and a qml view where items are added and removed dynamically but I'm not able to find one online. I'd really appreciate if someone could link it for me.
-
wrote on 21 Jan 2015, 16:15 last edited by
You are creating a model, but it goes out of scope immediately after constructor terminates (I suppose your last code snippet is in a constructor).
You should ensure that the model remains in existence while the QML view is showing, e. g. by allocating on heap:
@MyDataModel *myDataModel = new MyDataModel(this);
context->setContextProperty("myDataModel", myDataModel);@ -
wrote on 21 Jan 2015, 17:44 last edited by
I've tried to allocate it at the heap as well and the ui remains unchanged. Originally, myDatamodel was a private member of its parent's class. The code snippet was modified to simplify my question.
-
wrote on 21 Jan 2015, 19:44 last edited by
You are using "it's" wrongly. Have a look at http://www.elearnenglishlanguage.com/blog/english-mistakes/its/ . You have it also in the title.
-
wrote on 21 Jan 2015, 22:01 last edited by
:D Thanks for pointing that out!
-
bq. I just tried inserting that, and my Application Crashed as soon as that code was invoked. Narrowed it down to endResetModel() being the culprit.
I have been using this approach in all my projects where ListView is used. It worked all the time.
Why are you using QDeclarativeView ? Aren't you using Qt 5 ? -
wrote on 22 Jan 2015, 11:29 last edited by
[quote author="kwisatz" date="1421877712"]:D Thanks for pointing that out!
[/quote]
It's good that you fixed it :D -
wrote on 22 Jan 2015, 17:46 last edited by
Sorry, should have made this clear earlier on, I'm using Qt 4.8.4.
[quote author="p3c0" date="1421902494"]bq. I just tried inserting that, and my Application Crashed as soon as that code was invoked. Narrowed it down to endResetModel() being the culprit.
I have been using this approach in all my projects where ListView is used. It worked all the time.
Why are you using QDeclarativeView ? Aren't you using Qt 5 ?[/quote] -
Well then I'm not sure why it crashes. Qt 4.8.4 still is quite old in Qt4 series. Can you try it on Qt 4.8.6 ?
-
wrote on 29 Jan 2015, 21:29 last edited by
I've tried this with 4.8.6 but to no avail
At the moment, I'm unable to move to Qt5. I'm cross-compiling for an Embedded Linux System as well, there's a fair amount of porting involved to move to Qt5.
-
wrote on 2 Feb 2015, 17:21 last edited by
Okay, I did manage to get this to work finally.
When clearing data, I used:
@ beginResetModel();
m_data.clear();
endResetModel();@When removing an individual item in the data, I used:
@ beginRemoveRows(QModelIndex(), index, index);
m_data.removeAt(index);
endRemoveRows();@And I worked on this bit of code separately from my main application. Will have to see what kind of fun awaits when I merge the changes with the rest of the application ;)
Appreciate the help folks!
10/16