Cancel QML Transition animation inside GridView on width change - qt

I have a GridView element that needs to be resized. The problem is, if there is a move transition on the displaced delegates and the width of the GridView changes while the transition animation is in progress, the animating delegates end up in the wrong places. I tried calling complete() on the animation inside the transition when the width of the GridView changes (in order to jump to the final property values), but it has no effect. I also tried setting the enabled property of the transition to false and back to true but that does not "cancel" an animation in progress. How might one tell a transition to immediately force all the elements its animating to their destination values?
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
id: main_window
width: 1000
height: 1000
visible: true
Rectangle {
id: grid_container
width: 500
height: 280
color: "yellow"
GridView {
id: grid_view
width: parent.width
height: parent.height
cellWidth: grid_view.width / 5
cellHeight: 70
model: my_model
delegate: Rectangle {
width: grid_view.cellWidth
height: grid_view.cellHeight
color: index % 2 ? "red" : "blue"
border.width: 2
}
displaced: Transition {
NumberAnimation {
id: displaced_animation
properties: "x,y"
duration: 2000
}
}
onWidthChanged: {
displaced_animation.complete() // Does not work
}
}
}
Button {
x: 0
y: 400
width: 200
text: "Model Move Operation"
onClicked: {
var model = grid_view.model
model.move(0, model.count - 1, 1)
}
}
Button {
x: 250
y: 400
width: 200
text: "Change Grid Width"
onClicked: {
grid_container.width = Qt.binding(function(){ return main_window.width})
}
}
ListModel {
id: my_model
ListElement {
letter: "A"
}
ListElement {
letter: "B"
}
ListElement {
letter: "C"
}
ListElement {
letter: "D"
}
ListElement {
letter: "E"
}
ListElement {
letter: "F"
}
ListElement {
letter: "G"
}
ListElement {
letter: "H"
}
ListElement {
letter: "I"
}
ListElement {
letter: "J"
}
ListElement {
letter: "K"
}
ListElement {
letter: "L"
}
ListElement {
letter: "M"
}
ListElement {
letter: "N"
}
ListElement {
letter: "O"
}
ListElement {
letter: "P"
}
ListElement {
letter: "Q"
}
ListElement {
letter: "R"
}
ListElement {
letter: "S"
}
ListElement {
letter: "T"
}
}
}

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.

create Flickable and list view that start again at end

hello how o create list view that start again at end like (0-1-2-3...8-9-0-1-2) like loop
i used tumbler but it have some problem i need something like tumbler +wrap...........................................................................................................................................................................................
import QtQuick 2.12
import QtQuick.Layouts 1.12
import Qt.labs.folderlistmodel 2.12
Flickable{
width: 180; height: 200; color: "white"
Component {
id: delegate
Item {
id: wrapper
width: 180; height: 40
Column {
x: 5; y: 5
Text { text: '<b>Name:</b> ' + name }
}
}
}
ListView {
width: parent.width; height: parent.height
delegate: delegate
focus: true
model: ListModel {
id: contactModel
ListElement {
name: "1"
}
ListElement {
name: "2"
}
ListElement {
name: "3"
}
ListElement {
name: "4"
}
ListElement {
name: "5"
}
ListElement {
name: "6"
}
ListElement {
name: "7"
}
ListElement {
name: "8"
}
ListElement {
name: "9"
}
}
}
}

How to add a editable TableView header in qml?

import QtQuick 2.7
import QtQuick.Controls 1.3
import QtQuick.Controls.Styles 1.3
Rectangle {
width: 640
height: 480
ListModel {
id: tstModel
ListElement { animal: "dog" }
}
TableView {
id: tableView
anchors.fill: parent
model: tstModel
headerDelegate: Item{
height: 50
width: animalColumn.width
TextField{
text: styleData.value
anchors.fill: parent
}
}
TableViewColumn {
id: animalColumn
title: "Animal"
role: "animal"
width: 50
resizable: false
movable: false
}
}
}
This code is not acting as I expect. Textfield gets focus only when I am clicking the header with right button. And there is a Textfield works fine next to the first column header, but it's not what I want.
How to add a editable TableView header in qml?
I find this headerDelegate to be rather buggy or not supposed to be used in this scenario. I would rather implemnt a header from scrath to use for your use-case. Try this as a starting point:
Rectangle {
width: 640
height: 480
ListModel {
id: tstModel
ListElement { animal: "cat" }
ListElement { animal: "cat" }
ListElement { animal: "cat" }
ListElement { animal: "cat" }
ListElement { animal: "cat" }
ListElement { animal: "cat" }
ListElement { animal: "cat" }
}
TextField{
id: tableViewCustomHeader
property int curRow: tableView.currentRow
property bool isActual: curRow >= 0
function reloadText() { text = tstModel.get(curRow).animal }
function saveText() { tstModel.setProperty(curRow, "animal", text); tableView.model = tstModel; }
width: animalColumn.width
height: isActual ? 20 : 0
onCurRowChanged: {
if ( isActual >= 0 ) reloadText();
focus = true;
}
onTextChanged: if ( isActual >= 0 ) saveText()
}
TableView {
id: tableView
anchors {
top: tableViewCustomHeader.bottom
bottom: parent.bottom
left: parent.left
right: parent.right
}
model: tstModel
headerVisible: false
TableViewColumn {
id: animalColumn
title: "Animal"
role: "animal"
width: 200
resizable: false
movable: false
}
}
}
You can edit this anyway you want afterwards.
If it's a strict requirement to go with headerDelegate - this what I've end up with:
Rectangle {
width: 640
height: 480
ListModel {
id: tstModel
ListElement { animal: "dog" }
ListElement { animal: "cat" }
}
TableView {
id: tableView
anchors.fill: parent
model: tstModel
headerDelegate:
TextField{
property int curRow: tableView.currentRow
function reloadText() { text = tstModel.get(curRow).animal }
function saveText() { tstModel.setProperty(curRow, "animal", text); tableView.model = tstModel; }
onCurRowChanged: {
if ( curRow >= 0 ) reloadText()
}
onTextChanged: saveText()
width: parent.width
}
TableViewColumn {
id: animalColumn
title: "Animal"
role: "animal"
width: 200
resizable: false
movable: false
}
}
}
But, again, it works in a very strange way once you are adding TextField to it, so I would vote against it.

Disable draging of the view by pressing and holding a mouse button while moving the cursor

I want to disable the dragging of my List view using pressing and holding a mouse button while moving the cursor. I am trying to implement some other feature such as multiple selection using this command. I would only like the scrolling to be enabled. The interactive property of the flickable totally disables the movement of the view. Is there some workaround for this?
I guess there are some ways to achieve what you need, but the following solution works.
The idea is to have a MouseArea and set the interactive property to false when the signals onPressed and onClicked are emitted. interactive should be set to true again in the onReleased handler.
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ListModel {
id: listModel
ListElement {
name: "ttt"
number: "111"
}
ListElement {
name: "rrr"
number: "222"
}
ListElement {
name: "sss"
number: "333"
}
ListElement {
name: "xxx"
number: "444"
}
ListElement {
name: "yyy"
number: "555"
}
ListElement {
name: "zzz"
number: "666"
}
ListElement {
name: "aaa"
number: "777"
}
ListElement {
name: "bbb"
number: "888"
}
ListElement {
name: "ccc"
number: "999"
}
ListElement {
name: "ddd"
number: "011"
}
ListElement {
name: "eee"
number: "022"
}
ListElement {
name: "fff"
number: "033"
}
}
ListView {
id: myList
width: 180; height: 100
clip: true
Component {
id: contactsDelegate
Rectangle {
id: wrapper
width: 180
height: contactInfo.height
color: "lightblue"
Text {
id: contactInfo
text: name + ": " + number
color: "black"
}
MouseArea {
anchors.fill: parent
onPressed: {
myList.interactive = false
console.debug("onPressed")
}
onClicked: {
myList.interactive = false
console.debug("onClicked")
}
onReleased: {
myList.interactive = true
console.debug("onReleased")
}
}
}
}
model: listModel
delegate: contactsDelegate
focus: true
}
}

Is there easy way to duplicate a RowLayout in QtQuick?

In my ui.qml I have:
RowLayout {
id: rowLayout2
x: 0
y: 397
width: 640
height: 50
clip: false
Text {
id: text4
width: 105
height: 32
text: qsTr("房间类型")
font.pixelSize: 17
wrapMode: Text.WordWrap
}
ComboBox {
id: comboBox1
activeFocusOnPress: false
model: ListModel {
id: cbItems
ListElement { text: "标准间"; color: "Yellow" }
ListElement { text: "三人间"; color: "Green" }
ListElement { text: "大床房"; color: "Brown" }
ListElement { text: "豪华套房"; color: "Blue" }
}
}
}
And I want to make a button that when clicked on duplicates this RowLayout below the original one, how do I do that?
Put it inside a Repeater and increment the model count when the button is clicked.
Button {
onClicked: {
repeater.model += 1;
}
}
...
Column {
Repeater {
model: 1
// Your rowLayout2 code
}
}

Resources