Getting into PathView delegate - qt

I am trying to animate a property within my PathView delegate once it comes into view.
Component {
id: pathViewDelegate
Item {
Text {
id: tempText
color: "red"
text: "test"
}
function intoView() {
myAnimation.start()
}
SequentialAnimation {
id: myAnimation
PropertyAnimation {duration: 1000; target: tempText; properties: "color"; to: "green"}
PropertyAnimation {duration: 1000; target: tempText; properties: "color"; to: "yellow"}
}
}
}
The only way I know how to display my PathView correctly (like a linear carousel) is to have the currentItem clipped off screen. In other words, the displayed item is always currentIndex+1 in my PathView.
PathView {
id: mainCarousel
width: parent.width
height: parent.height
interactive: false
highlightMoveDuration: 300
clip: true
model: pathViewModel
delegate: pathViewDelegate
path: Path {
startX: -mainCarousel.width*0.5
startY: mainCarousel.height/2
PathLine { x: mainCarousel.width*0.5; y: mainCarousel.height/2 }
PathLine { x: mainCarousel.width*(mainCarousel.count-0.5); y: mainCarousel.height/2 }
}
}
}
So, when I try to implement a function with "mainCarousel.currentItem.intoView()", it animates the item clipped off screen. I know there isn't a way to do "currentItem+1", but is there some other workaround?
EDIT: Full example code
ListModel {
id: pathViewModel
ListElement {header: "text 1"}
ListElement {header: "text 2"}
ListElement {header: "text 3"}
ListElement {header: "text 4"}
}
Component {
id: pathViewDelegate
Item {
width: mainCarousel.width
height: mainCarousel.height
Text {
color: "red"
text: header
}
function runAnimation() {
myAnimation.start()
}
SequentialAnimation {
id: myAnimation
PropertyAnimation {property: "color"; to: "green"; duration: 1000}
PropertyAnimation {property: "color"; to: "yellow"; duration: 1000}
PropertyAnimation {property: "color"; to: "purple"; duration: 1000}
}
}
}
PathView {
id: mainCarousel
width: 500
height: 500
interactive: false
highlightMoveDuration: 300
clip: true
model: pathViewModel
delegate: pathViewDelegate
path: Path {
startX: -mainCarousel.width*0.5
startY: mainCarousel.height/2
PathLine { x: mainCarousel.width*0.5; y: mainCarousel.height/2 }
PathLine { x: mainCarousel.width*(mainCarousel.count-0.5); y: mainCarousel.height/2 }
}
}
MouseArea {
id: telltaleMouseArea
anchors.fill: mainCarousel
onClicked: {
mainCarousel.incrementCurrentIndex()
mainCarousel.currentItem.runAnimation()
}
}
The initial item displayed is "text 2". The currentItem is "text 1", initially. In the code, when the MouseArea is clicked, "text 2" animates, but it is off screen. I am just trying to animate the item that is in view, when it becomes into view.

Change the animation to the following:
Text {
color: "red"
text: header
SequentialAnimation on color{
id: myAnimation
ColorAnimation {
to: "green"
duration: 1000
}
ColorAnimation {
to: "yellow"
duration: 1000
}
ColorAnimation {
to: "purple"
duration: 1000
}
}
}
and make sure your currentItem is in view with : startX: mainCarousel.width*0.5

Related

QML: how to scroll scrollview using the mouse wheel

I need to ensure that the ListView scrolls not only when hovering over it, but also in the area around it. As in the picture
I tried to do it like this, but scrolling with the mouse wheel still doesn't work
import QtQuick 2.0
import QtQuick.Controls 2.3
Rectangle {
height: 400
width: 300
color: "steelblue"
ScrollView {
anchors.fill: parent
wheelEnabled: true
ListView {
id: listView
anchors { fill: parent; margins: 40}
clip: true
model: appModel
delegate: Rectangle {
height: 50
width: listView.width
color: colorR
}
}
}
ListModel {
id: appModel
ListElement { colorR: "red"}
ListElement { colorR: "green"}
ListElement { colorR: "blue"}
ListElement { colorR: "cyan"}
ListElement { colorR: "yellow"}
ListElement { colorR: "blue"}
ListElement { colorR: "lightgray"}
ListElement { colorR: "red"}
ListElement { colorR: "green"}
ListElement { colorR: "blue"}
ListElement { colorR: "cyan"}
ListElement { colorR: "yellow"; }
ListElement { colorR: "lightgray"}
}
}
You can use WheelHandler outside the ListView
import QtQuick
import QtQuick.Controls
Rectangle {
height: 400
width: 300
color: "green"
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
WheelHandler {
onWheel: (event)=>{listView.flick(0, event.angleDelta.y*event.y)}
}
ListView {
id: listView
anchors { fill: parent; margins: 40}
model: 50
spacing: 10
delegate: Rectangle {
height: 50
width: listView.width
color: getRandomColor()
}
}
}
You can try this online.

How to trigger Animation on one Item in a ListView

I try to trigger a SequentialAnimation on a given Item of a ListView.
For example:
ApplicationWindow {
id: window
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ListModel {
id: modelList
ListElement {}
ListElement {}
ListElement {}
}
ListView {
width: window.width
height: window.height
model: modelList
delegate: Rectangle {
width: window.width
height: window.height/10
color: "red"
radius : 10
SequentialAnimation on color { //Should be only triggered when button clicked
ColorAnimation { to: "yellow"; duration: 1000 }
ColorAnimation { to: "red"; duration: 1000 }
}
Button {
text: "trigger animation"
anchors{
right: parent.right
top: parent.top
bottom: parent.bottom
margins: 10
}
onClicked: {
//Trigger SequentialAnimation
}
}
}
}
}
I try to trigger the Animation when you click on the button but I don't know how to use a condition on an Animation.
How could I proceed ?
Use animation on property only if you want changes to be automatically animated.
In your case you need to remove the on color part, then give the animation an id: yourAnimation, and on the button click yourAnimation.start()
Actually, it seems that on color is also possible, skipping setting the target:
SequentialAnimation on color {
id: yourAnimation
ColorAnimation { to: "yellow"; duration: 1000 }
ColorAnimation { to: "red"; duration: 1000 }
running: false
}

Horizontal listview navigation - visible item

I have more horizontal listview. For example let's take two of them. Items of each list are not the same length, when one list is scrolling - the other one does, too. I've solved that with contentX property. But, when I want to navigate between each other (when I press key "down" I need to force focus second listview). The problem is that focus is on horizontalna2.currentIndex that is remembered, and I want to go on first visible item in listview.
In android is that very simple, but to solve that here, huh..
Here is sketch of the code:
Rectangle {
width: 500
height: 200
ListModel {
id: model1
ListElement { itemwidth: 100 }
ListElement { itemwidth: 200 }
ListElement { itemwidth: 50 }
ListElement { itemwidth: 70 }
ListElement { itemwidth: 90 }
ListElement { itemwidth: 90 }
ListElement { itemwidth: 90 }
ListElement { itemwidth: 90 }
ListElement { itemwidth: 90 }
ListElement { itemwidth: 90 }
}
ListModel {
id: model2
ListElement { itemwidth: 300 }
ListElement { itemwidth: 50 }
ListElement { itemwidth: 70 }
ListElement { itemwidth: 100 }
ListElement { itemwidth: 90 }
ListElement { itemwidth: 30 }
ListElement { itemwidth: 90 }
ListElement { itemwidth: 90 }
ListElement { itemwidth: 90 }
ListElement { itemwidth: 90 }
}
ListView {
clip: true
id: horizontalna
boundsBehavior: Flickable.StopAtBounds
width: 500
height: 60;
focus: true
model: model1
orientation: ListView.Horizontal
KeyNavigation.down: horizontalna2
onContentXChanged: {
if (horizontalna.activeFocus === true)
{
horizontalna2.contentX = horizontalna.contentX
}
}
delegate: Item {
id: containerHorizontal
width: itemwidth; height: 60;
Rectangle {
id: contentHorizontal
anchors.centerIn: parent; width: containerHorizontal.width; height: containerHorizontal.height - 10
color: "transparent"
antialiasing: true
Rectangle { id: insideConHorizontal; anchors.fill: parent; anchors.margins: 3; color: "grey"; antialiasing: true; radius: 5
Text {
id: labelHorizontal
text: "name"
color: "white"
}
}
}
states: State {
name: "active"; when: containerHorizontal.activeFocus
PropertyChanges { target: contentHorizontal; color: "#FFFF00"; scale: 1}
PropertyChanges { target: insideConHorizontal; color: "#F98F06" }
PropertyChanges { target: labelHorizontal; color: "#0E2687"}
}
}
}
ListView {
id: horizontalna2
anchors.top: horizontalna.bottom
boundsBehavior: Flickable.StopAtBounds
width: 500
height: 60;
focus: true
model: model2
orientation: ListView.Horizontal
onContentXChanged: {
if (horizontalna2.activeFocus === true)
{
horizontalna.contentX = horizontalna2.contentX
}
}
delegate: Item {
id: containerHorizontal2
width: itemwidth; height: 60;
Rectangle {
id: contentHorizontal2
anchors.centerIn: parent; width: containerHorizontal2.width; height: containerHorizontal2.height - 10
color: "transparent"
antialiasing: true
Rectangle { id: insideConHorizontal2; anchors.fill: parent; anchors.margins: 3; color: "grey"; antialiasing: true; radius: 5
Text {
id:labelHorizontal2
color: "white"
text: "name"
}
}
}
states: State {
name: "active"; when: containerHorizontal2.activeFocus
PropertyChanges { target: contentHorizontal2; color: "#FFFF00"; scale: 1}
PropertyChanges { target: insideConHorizontal2; color: "#F98F06" }
PropertyChanges { target: labelHorizontal2; color: "#0E2687"}
}
}
}
}
EDIT[SOLVED] :
Get index of first visible item of second list depending on contentX --> function indexAt()
onCurrentIndexChanged: {
if (horizontalna.activeFocus === true)
{
horizontalna2.currentIndex = horizontalna2.indexAt((horizontalna2.contentX),0)
}
}
Get index of first visible item of second list depending on contentX --> function indexAt()
onCurrentIndexChanged: {
if (horizontalna.activeFocus === true)
{
horizontalna2.currentIndex = horizontalna2.indexAt((horizontalna2.contentX),0)
}
}

make QML TextField to blinking

I want TextField to blink when button is clicked. It easy to do with QTimer:
void MyLineEdit::buttonClickedSlot{
for(int i=1;i<15;i+=2){
QTimer::singleShot(100*i, this, SLOT(changeBackgroundColor("QLineEdit{background: red;}")));
QTimer::singleShot(100*(i+1), this, SLOT((changeBackgroundColor("QLineEdit{background: white;}")));
}
}
void MyLineEdit::changeBackgroundColor(QString str){
this->setStyleSheet(str)
}
However, I did not find anything like QTimer in QML so I decided to do it via animation. Here QML is code:
Rectangle{
ColumnLayout{
anchors.fill: parent
TextField{
id: txt
text: "hello"
style: TextFieldStyle{
background:Rectangle {
id: rect
radius: 2
implicitWidth: 100
implicitHeight: 24
border.color: "#333"
border.width: 1
color: "white"
}
}
}
ColorAnimation{
id: whiteToRed
target: rect //reference error: rect is not defined
properties: "color"
from: "white"
to: "red"
duration: 300
}
ColorAnimation{
id: redToWhite
target: rect //reference error: rect is not defined
properties: "color"
from: "red"
to: "white"
duration: 300
}
Button{
text: "blink"
onClicked: {
for(var i=0;i<3;i++){
whiteToRed.start()
redToWhite.start()
}
}
}
}
}
The problem here is that there are compile error: rect is not defined. How should I solve that problem?
Try this:
Column{
anchors.fill: parent
TextField{
id: txt
text: "hello"
property string color: "white"
style: TextFieldStyle{
background: Rectangle {
id: rect
radius: 2
implicitWidth: 100
implicitHeight: 24
border.color: "#333"
border.width: 1
color: txt.color
Behavior on color {
SequentialAnimation {
loops: 3
ColorAnimation { from: "white"; to: "red"; duration: 300 }
ColorAnimation { from: "red"; to: "white"; duration: 300 }
}
}
}
}
}
Button{
text: "blink"
onClicked: {
txt.color = "red";
txt.color = "white";
}
}
}

ListView issue in QML

I'm trying to develop an application which has multi-layered navigation in drop-downs.
Below is the snapshot of the requirement. On clicking QSR only the subitems of QSR should pop out with proper alignment.
But with my implementation, I'm getting following result. The pop out window is not aligned, but extending itself to the list.
Below is the my code snippet
import QtQuick 1.1
Item {
width: 500
height: 300
ListView {
anchors.fill: parent
model: nestedModel
delegate: categoryDelegate
}
ListModel {
id: nestedModel
ListElement {
categoryName: "QSR"
collapsed: true
subItems: [
ListElement { itemName: "KFC" },
ListElement { itemName: "Mc Donalds" },
ListElement { itemName: "Pizza Hut" },
ListElement { itemName: "Brain's" }
]
}
ListElement {
categoryName: "Drinks"
collapsed: true
subItems: [
ListElement { itemName: "Pepsi" },
ListElement { itemName: "Coke" },
ListElement { itemName: "7up" },
ListElement { itemName: "Bacardi" }
]
}
}
Component {
id: categoryDelegate
Column {
width: 200
Rectangle {
id: categoryItem
border.color: "black"
border.width: 5
color: "white"
height: 50
width: 200
anchors.left: parent.right
Text {
anchors.right: parent.right
x: 15
font.pixelSize: 24
text: categoryName
}
MouseArea {
anchors.fill: parent
onClicked: nestedModel.setProperty(index, "collapsed", !collapsed)
}
}
Loader {
id: subItemLoader
visible: !collapsed
property variant subItemModel : subItems
sourceComponent: collapsed ? null : subItemColumnDelegate
onStatusChanged: if (status == Loader.Ready) item.model = subItemModel
}
}
}
Component {
id: subItemColumnDelegate
Column {
property alias model : subItemRepeater.model
width: 200
Repeater {
id: subItemRepeater
delegate: Rectangle {
color: "#cccccc"
height: 40
width: 200
border.color: "black"
border.width: 2
Text {
anchors.verticalCenter: parent.verticalCenter
x: 30
font.pixelSize: 18
text: itemName
}
}
}
}
}
}
Any help to achieve original requirement will be appreciable.
Have a close look at the delegate for your main list view: It's Column (put items on top of each over) of the main menu item and Loader for the popup menu. Obviously as soon as you load a popup menu it's displayed under its corresponding menu item in the list.
To get the behavior you intended you have to move the Loader for the popup menu out of the ListView:
import QtQuick 1.1
Item {
width: 400
height: 300
Row {
anchors.fill: parent
Loader {
id: subItemLoader
width: 200
height: parent.height
property variant subItemModel: null
sourceComponent: subItemModel == null? null: subItemColumnDelegate
function setModel() {
if (status == Loader.Ready) item.model = subItemModel
}
onStatusChanged: setModel()
onSubItemModelChanged: setModel()
}
ListView {
width: 200
height: parent.height
model: nestedModel
delegate: categoryDelegate
}
}
ListModel {
id: nestedModel
ListElement {
categoryName: "QSR"
subItems: [
ListElement { itemName: "KFC" },
ListElement { itemName: "Mc Donalds" },
ListElement { itemName: "Pizza Hut" },
ListElement { itemName: "Brain's" }
]
}
ListElement {
categoryName: "Drinks"
subItems: [
ListElement { itemName: "Pepsi" },
ListElement { itemName: "Coke" },
ListElement { itemName: "7up" },
ListElement { itemName: "Bacardi" }
]
}
}
Component {
id: categoryDelegate
Rectangle {
id: categoryItem
border.color: "black"
border.width: 5
color: "white"
height: 50
width: 200
Text {
anchors.centerIn: parent
x: 15
font.pixelSize: 24
text: categoryName
}
MouseArea {
anchors.fill: parent
onClicked: {
if (subItemLoader.subItemModel != subItems)
subItemLoader.subItemModel = subItems
else
subItemLoader.subItemModel = null
}
}
}
}
Component {
id: subItemColumnDelegate
Column {
property alias model : subItemRepeater.model
width: 200
height: 500
Repeater {
id: subItemRepeater
delegate: Rectangle {
color: "#cccccc"
height: 40
width: 200
border.color: "black"
border.width: 2
Text {
anchors.verticalCenter: parent.verticalCenter
x: 30
font.pixelSize: 18
text: itemName
}
}
}
}
}
}

Resources