GridView and transitions not working
-
Hi, I'm trying to get my GridView to animate transitions on operations performed on my C++ model (exposed as a QQmlListProperty). But they don't work.
The following snippet works:
@ GridView {
id: gridview
anchors.fill: parent
cellWidth: width / 3
cellHeight: height / 3model: ListModel {
id: model2
ListElement {
name: "red"
}
ListElement {
name: "blue"
}
ListElement {
name: "green"
}
ListElement {
name: "tomato"
}
}delegate: Item {
id: gridDelegate
width: gridview.cellWidth
height: gridview.cellHeightRectangle {
id: image
anchors.fill: parent
color: name
Behavior on color {
PropertyAnimation { duration: 1000 }
}
}Image {
width: parent.width / 10
height: width
anchors {
right: image.right
rightMargin: 10
bottom: image.bottom
bottomMargin: 10
}
source: "delete-icon.png"
antialiasing: true
opacity: mouseArea.containsMouse ? 1 : 0
Behavior on opacity {
NumberAnimation { duration: 200 }
}
MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true
onClicked: model2.remove(index);
}
}
}
// Transitions
remove: Transition {
ParallelAnimation {
NumberAnimation { property: "opacity"; to: 0; duration: 500 }
NumberAnimation { properties: "width, height"; to: 0; duration: 500 }
}
}
removeDisplaced: Transition {
NumberAnimation { properties: "x, y"; duration: 500 }
}
}
@
The following does not:
@ GridView {
id: gridview
anchors.fill: parent
cellWidth: width / 3
cellHeight: height / 3-
model: imageLoader.allImages*
delegate: Item {
id: gridDelegate
width: gridview.cellWidth
height: gridview.cellHeight -
Image {
id: image
width: parent.width - anchors.margins / 2
height: status == Image.Ready ? parent.height - anchors.margins / 2 : 0
anchors {
centerIn: parent
margins: 10
}
Behavior on height {
NumberAnimation { duration: 500; easing.type: Easing.InOutQuad }
}
fillMode: Image.PreserveAspectFit
asynchronous: true
source: "file:///" + path
} -
Image {
width: parent.width / 10
height: width
anchors {
right: image.right
rightMargin: 10
bottom: image.bottom
bottomMargin: 10
}
source: "delete-icon.png"
antialiasing: true
opacity: mouseArea.containsMouse ? 1 : 0
Behavior on opacity {
NumberAnimation { duration: 200 }
}MouseArea {
id: mouseArea
anchors.fill: parent
hoverEnabled: true -
onClicked: imageLoader.remove_all_image(index);*
}
}
}
// Transitions
remove: Transition {
ParallelAnimation {
NumberAnimation { property: "opacity"; to: 0; duration: 500 }
NumberAnimation { properties: "width, height"; to: 0; duration: 500 }
}
}
removeDisplaced: Transition {
NumberAnimation { properties: "x, y"; duration: 500 }
}
}
@
I've highlighted the differences: in the first case, the model is a dedicated ListModel QML element.
In the second case, it's a QQmlListProperty I expose from C++.
I think the problem is with the slot I call from C++ when clicking the delete-icon:
@* onClicked: imageLoader.remove_all_image(index);*@
which is as follows in the code behind:
@void ImageLoader::remove_all_image(int i)
{
m_allImages.removeAt(i);
emit allImagesChanged();
}
@
I have the feeling that GridView's transitions remove and removeDisplaced are only triggered by a call to the remove function in the ListModel, which fires the proper signals, whereas my function just emits the NOTIFY signal for the QQmlListProperty change and this forces a refresh of the whole Grid. I also noticed that removing an element from the ListModel maintains the currentIndex, whereas calling my function resets the currentIndex to 0 (and if I remove and element from the bottom of the GridView, the grid scroll back to top...).So, how can I work this problem around? If I got it right, QQmlListProperty wraps QList<MyCustomQObject*> and offers the append function, the count, the access and the clear function, but no removeAt function (which is why I implemented it manually), how can I get this functionality?? The documentation is quite lacking...
-
-
"Note that objects cannot be individually added to or removed from the list once created; to modify the contents of a list, it must be reassigned to a new list.":http://qt-project.org/doc/qt-5/qml-list.html
-
Which is what happens when I call the C++ api: the underlying QList<MyImage*> is modified, then the allImagesChanged(); signal fires and the QQmlListProperty getter is called again. Or not?
In any case, should I dive into the study of QAbstractListModel as an alternative to QQmlListProperty?
-
I think you misunderstand QQmlListProperty. QQmlListProperty is list in QML. It is not a model. QAbstractListModel is a model class.
I think you should use a model.
-
I first used a list because I only need to show in the UI the data fetched by the C++ engine. So I started with a raw
@QPROPERTY(QList<QObject*> allImages READ ... )@
then switched to
@QPROPERTY(QQmlListProperty<MyImage> allImages READ ... )@
Both approaches worked and were simple enough...and since I'm quite new to this framework, I didn't want to complicate things from the start...I'll try to subclass QAbstractListModel now... anyway I'm still curious to know the exact mechanics that lead to my problem :)
-
Ok so, I got my model to work! Wasn't that hard after all, as this class (QAbstractListModel) is quite documented over the internet, as opposed to QQmlListProperty...
Anyway, now there's one other thing which is not working: the elements returned by my model have one read AND write property, which only works in read mode. I cannot, from QML, write to it implicitly:
@// Inside the GridView delegate:
onClicked: favorite = !favorite;@
This won't work. I have to call an invokable method (or better, a public Q_SLOT):
@// Inside the GridView delegate:
onClicked: gridview.model.get(index).set_favorite(!favorite);@Has anyone an idea why writing to properties doesn't work?
edit: also the notification doesn't seem to work...
-
please show your complete code.
-
I now understand why, in the QML, writing in the grid delegate:
@onClicked: myProperty = newValue@
does not work: it's because myProperty, exposed to QML, is actually a role, not the real property...that's why I should explicitly use the setter for that property. I'll see if I can do anything with the Qt::EditRole token...Edit: I have overridden QAbstractListIModel::setData with my own implementation and... voilĂ ! Everything working like a charme! There had to be a way ;)