QML listview Transition does not work for C++ Model - qml

I have tried this example for add animation.It works
ListView {
width: 240; height: 320
model: ListModel {}
delegate: Rectangle {
width: 100; height: 30
border.width: 1
color: "lightsteelblue"
Text {
anchors.centerIn: parent
text: name
}
}
add: Transition {
NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 400 }
NumberAnimation { property: "scale"; from: 0; to: 1.0; duration: 400 }
}
displaced: Transition {
NumberAnimation { properties: "x,y"; duration: 400; easing.type: Easing.OutBounce }
}
focus: true
Keys.onSpacePressed: model.insert(0, { "name": "Item " + model.count })
}
When new record is inserted in model , add anim works perpeftly.But I want to refer model to C++ list like:
model:mymodel.list
When I add new record to list , listmodel is updated but add animation not take effect
I Find Solution by using QAbstractItemModel

Related

How to animate scroll in a QML ScrollView?

How can I animate scrolling in a QML ScrollView?
I've tried a Behavior on the contentItem.contentY, but that isn't working.
With Qt Quick Controls 1
You just have to animate the value changes on the property flickableItem.contentY.
A quick example:
Item {
anchors.fill: parent
ColumnLayout {
anchors.fill: parent
Button {
id: btn
onClicked: scroll.scrollTo(scroll.flickableItem.contentY + 100)
}
ScrollView {
id: scroll
function scrollTo(y) {
scrollAnimation.to = y
scrollAnimation.start()
}
NumberAnimation on flickableItem.contentY {
id: scrollAnimation
duration: 1000
}
contentItem: Column {
Repeater {
model: 30
Rectangle {
width: 100; height: 40
border.width: 1
color: "yellow"
}
}
}
}
}
}
When you click on the button, it will scroll by 100 px with a smooth jump.
With Qt Quick Controls 2
The flickableItem.contentY isn't available anymore. The simpliest way to do the same thing in Qt Quick Controls 2 is to animate the position of the ScrollBar.
Notice that the position of QScrollBar is in percent (expressed between 0 and 1), not in pixels.
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ScrollView {
id: scroll
width: 200
height: 200
clip: true
function scrollTo(y) {
scrollAnimation.to = y
scrollAnimation.start()
}
ScrollBar.vertical: ScrollBar {
id: test
parent: scroll
x: scroll.mirrored ? 0 : scroll.width - width
y: scroll.topPadding
height: scroll.availableHeight
active: scroll.ScrollBar.horizontal.active
policy: ScrollBar.AlwaysOn
NumberAnimation on position {
id: scrollAnimation
duration: 1000
}
}
ListView {
model: 20
delegate: ItemDelegate {
text: "Item " + index
}
}
}
Button {
id: btn
anchors.top: scroll.bottom
onClicked: scroll.scrollTo(test.position + 0.1)
}
}
When you click on the button, it will scroll by 10% of the height.

How to skip drawing an item when a Grid is populated via an Repeater in qml?

I want to fill a Grid with a Repeater but not all cells should get an Item. How to do that?
Rectangle {
id: base
Grid {
id: grid
anchors.fill: parent
columns: 30
rows: 20
Repeater {
model: grid.columns * grid.rows
delegate: Item {
// How to skip this at row 5, column 3, for example
width: grid.width / grid.columns
height: grid.height / grid.rows
}
}
}
}
This is basically the same problem, as how can I have different delegates in a Repeater depending on the model's data with the special case: The delegate is empty.
For this more general approach, you can use dynamic object creation like this:
Window {
id: root
visible: true
width: 400; height: 400
// delegate 0 is skipped, 1 is circle, 2 is quadrangle
ListModel {
id: lm
ListElement { delegate: 0 }
ListElement { delegate: 1; color: 'red' }
ListElement { delegate: 2; color: 'green' }
ListElement { delegate: 1; color: 'blue' }
ListElement { delegate: 0 }
ListElement { delegate: 0 }
ListElement { delegate: 1; color: 'orchid' }
ListElement { delegate: 0 }
ListElement { delegate: 1; color: 'red' }
ListElement { delegate: 2; color: 'green' }
ListElement { delegate: 1; color: 'blue' }
ListElement { delegate: 0 }
ListElement { delegate: 0 }
ListElement { delegate: 1; color: 'orchid' }
}
Grid {
anchors.fill: parent
columns: 5
Repeater {
id: rep
property var delegates: [function() { console.log('skipped'); return null }, circ.createObject, rect.createObject ]
model: lm
delegate: Item {
width: (delegate ? delegate.width : 1)
height: (delegate ? delegate.height : 1)
property var delegate: rep.delegates[model.delegate](this, { color: model.color })
}
}
}
Component {
id: circ
Rectangle {
width: 20
height: 20
radius: 10
}
}
Component {
id: rect
Rectangle {
width: 20
height: 20
}
}
}
Of course you can use any cirterium and method to chose, whether or which delegate should be used. The ListModel and list of functions just seems to be convenient in lots of cases. You can also just use a switch-statement or anything else.
Instead of using the JS-function you could also use a Loader as toplevel element, and set or not set a source. You only need to make sure the toplevel delegate has dimensions (at least width and height of 1) otherwise the positioners (Grid/Column/Row) will ignore their existence.
The advantage of the dynamic creation is, that if the delegate is complex, it won't be created and just turned invisible, as it would be with the solution of Tony Clifton
You can't really "skip" a delegate's creation. You can use index to determine which item(s) to hide. If you want an "empty" gap in the grid set opacity to 0. If you want it "completely" gone, set visible to false.
Repeater {
model: grid.columns * grid.rows
delegate: Rectangle {
// How to skip this at row 5, column 3
// 4 * columns + 2 = 122 // 4 & 3 because of zero based counting.
color: "red"
opacity: index !== 122 ? 1 : 0
width: (grid.width / grid.columns) - 1
height: (grid.height / grid.rows) - 1
Text {
anchors.centerIn: parent
text: index
}
}
}

How to highlight the clicked (by mouse) element of a delegate w.r.t FolderListModel?

import QtQuick 2.0
import Qt.labs.folderlistmodel 2.0
Item
{
Component {
id: highlight
Rectangle {
id: rooot
width: 180; height: 20
color: ListView.isCurrentItem ? "black" : "red"; radius: 5
y: list.currentItem.y
Behavior on y {
SpringAnimation {
spring: 3
damping: 0.2
}
}
}
}
ListView {
id: list
width: 480; height: 400
model: folderModel
delegate: Text { id: h; text: fileName }
highlight: highlight
highlightFollowsCurrentItem: false
focus: true
}
FolderListModel
{
id: folderModel
folder: "/home/anisha/"
nameFilters: ["*"]
}
}
This works only when I use keyboard. How to make it work on mouse clicks?
To react on mouse events you need to place MouseArea item.
In the sample below (being an expanded version of the code you provided) I have added a MouseArea to the delegate item that upon being clicked sets the ListView's currentIndex to the delegate's index (a special property visible in the ListView's delegate).
import QtQuick 2.0
import Qt.labs.folderlistmodel 2.0
Item
{
Component {
id: highlight
Rectangle {
id: rooot
width: 180; height: 20
color: ListView.isCurrentItem ? "black" : "red"; radius: 5
y: list.currentItem.y
Behavior on y {
SpringAnimation {
spring: 3
damping: 0.2
}
}
}
}
ListView {
id: list
width: 480; height: 400
model: folderModel
delegate:
Text {
id: h;
text: fileName
MouseArea {
anchors.fill: parent
onClicked: list.currentIndex = index
}
}
highlight: highlight
highlightFollowsCurrentItem: false
focus: true
}
FolderListModel
{
id: folderModel
folder: "/home/anisha/"
nameFilters: ["*"]
}
}
As an alternative approach you might try placing a single MouseArea filling the whole ListView and use ListView's indexAt(int x, int y) method to check which delegate was clicked. However, you would need to care about more edge-conditions in such case.

Scale Element in StateELement

I can write lines below and got it work:
states: State {
name: "active"; when:myitem.activeFocus;
PropertyChanges { target: myitem; z:1000; scale: 1.2 }
}
transitions: Transition {
NumberAnimation { properties: scale; duration: 1000 }
}
But in these lines i can not give specific origin to scale property!
I found Scale Element
transform: Scale { origin.x: 25; origin.y: 25; xScale: 3}
How can i inject this into state property above, because i want to use "when" property of state,
i want scaling to run on that "when" condition.
Or is there any other way to scale in a condition with specifying origins?
Thanks for any idea.
You should set an id for the Scale element. Then you can change its properties in the "active" state.
Here a minimal working example:
import QtQuick 1.0
Item {
height: 200; width: 500
Rectangle {
id: myitem
height: 10; width: 100
anchors.centerIn: parent
color: "blue"
transform: Scale { id: scaleTransform; origin.x: 25; origin.y: 25 }
states: State {
name: "active"; when: mouseArea.pressed
PropertyChanges { target: scaleTransform; xScale: 3 }
}
transitions: Transition {
NumberAnimation { property: "xScale"; duration: 1000 }
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
}
}
Another possibility without states could be:
import QtQuick 1.0
Item {
height: 200; width: 500
Rectangle {
id: myitem
height: 10; width: 100
anchors.centerIn: parent
color: "blue"
transform: Scale {
id: scaleTransform
origin.x: 25; origin.y: 25
xScale: mouseArea.pressed ? 3 : 1 // <-
Behavior on xScale { // for animation
NumberAnimation { duration: 1000 }
}
}
}
MouseArea {
id: mouseArea
anchors.fill: parent
}
}
xScale is set to 3 when mouse is pressed, else to 1 (if you don't know the " ternary operation" look here).

how to use one model in two views

i have one model for pictures and want to show them in grid view or list view (fullscreen) synchronously. if user clicks on one image in grid view i want this image to be shown in fullscreen mode (in listview).
i have one solution but my list view scrolls till "the current index".
THanx.
PhotoView.qml
Rectangle {
width: settings.pageWidth
height: settings.pageHeight
anchors.fill: parent
VisualDataModel {
id: visualModel
delegate: PhotoDelegate {}
model: photosModel
}
ListView {
id:fullscreen
anchors.fill: parent;
orientation: ListView.Horizontal
snapMode: ListView.SnapOneItem;
flickDeceleration: 500
//highlightFollowsCurrentItem: true
highlightRangeMode: ListView.StrictlyEnforceRange
preferredHighlightBegin: 0; preferredHighlightEnd: 0
cacheBuffer: width;
spacing: settings.largeMargin
model: visualModel.parts.grid
}
GridView{
id:grid
width: settings.pageWidth
height: settings.pageHeight
anchors.fill: parent
cellWidth: settings.gridCellWidth
cellHeight: settings.gridCellHeight
snapMode: GridView.SnapToRow
cacheBuffer: settings.pageHeight
clip: true
model: visualModel.parts.grid
}
// // Menu/Back Button
// IconButton{
// id: backButton
// iconSource: "qrc:///gfx/back_arrow.png"
// anchors.right: parent.right
// anchors.bottom: parent.bottom
// onClicked: mainWindow.close();
// }
// Fade Top
Image{
id:bottom_fade
source: "qrc:///gfx/bottom-page-fade.png"
height: 33
width: settings.pageWidth
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
}
// Fade Bottom
Image{
id:top_fade
source: "qrc:///gfx/top-page-fade.png"
height: 33
width: settings.pageWidth
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
}
}
PhotoDelegate.qml
import QtQuick 1.0
import Qt 4.7
import "../views"
import "../model"
import "../views/components"
Package {
Item { id: listDelegate; Package.name: 'list'; width: settings.pageWidth; height: settings.pageHeight }
Item { id: gridDelegate; Package.name: 'grid'; width: settings.pageWidth; height: settings.pageHeight }
Item {
id: wrapper
width: settings.pageWidth; height: settings.pageHeight
Image {
id: thumbnail; smooth: true; source: thumbnail_url
}
MouseArea {
anchors.fill: parent
onClicked: {
if (wrapper.state == 'inGrid') {
listDelegate.fullscreen.view.currentIndex = index;
wrapper.state = 'fullscreen'
} else {
gridDelegate.grid.view.currentIndex = index;
wrapper.state = 'inGrid'
}
}
}
state: 'inGrid'
states: [
State {
name: 'fullscreen'
ParentChange { target: wrapper; parent: listDelegate; x: 0; y: 0;
width: listDelegate.width; height: listDelegate.height
}
},
State {
name: 'inGrid'
ParentChange {
target: wrapper; parent: gridDelegate
x: 0; y: 0; width: gridDelegate.width; height: gridDelegate.height
}
}
]
transitions: [
Transition {
from: 'inGrid'; to: 'fullscreen'
SequentialAnimation {
PauseAnimation { duration: gridItem.GridView.isCurrentItem ? 0 : 600 }
ParentAnimation {
target: wrapper; via: foreground
NumberAnimation {
targets: [ wrapper]
properties: 'x,y,width,height,opacity'
duration: gridItem.GridView.isCurrentItem ? 600 : 1; easing.type: 'OutQuart'
}
}
}
},
Transition {
from: 'fullscreen'; to: 'inGrid'
ParentAnimation {
target: wrapper; via: foreground
NumberAnimation {
targets: [ wrapper ]
properties: 'x,y,width,height,opacity'
duration: gridItem.GridView.isCurrentItem ? 600 : 1; easing.type: 'OutQuart'
}
}
}
]
}
}
To showing selected item without scrolling until index of selected item is to synchronize the view elements current index:
onCurrentIndexChanged: {
your_component.positionViewAtIndex(currentIndex, YourViewElement.Contain)
}