QML animation for Menus - qt

I want to animate a context menu during popup.I've used the Behavior QML type but that doesn't work for me:
Menu {
Behavior on width{
NumberAnimation{
duration: 200
}
}
Behavior on height{
NumberAnimation{
duration: 200
}
}
id: contextMenu
MenuItem { text: "Cut" }
MenuSeparator{}
MenuItem { text: "Copy" }
MenuItem { text: "Paste" }
}
Also using contentHeight or implicitHeight instead of height doesn't work either.
Any idea?

Menu is a Popup, and all popups support enter and exit transitions. To animate a menu opening, for example:
import QtQuick 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
visible: true
width: 640
height: 480
Button {
text: "Open menu"
onClicked: contextMenu.open()
}
Menu {
id: contextMenu
enter: Transition {
ParallelAnimation {
NumberAnimation { property: "width"; from: 0.0; to: contextMenu.implicitWidth }
NumberAnimation { property: "height"; from: 0.0; to: contextMenu.implicitHeight }
}
}
MenuItem { text: "Cut" }
MenuSeparator {}
MenuItem { text: "Copy" }
MenuItem { text: "Paste" }
}
}
The benefit of using implicitWidth and implicitHeight is that you won't have to declare properties to store the initial values of width and height in order to avoid them being overwritten by other animations, as you would with the accepted answer.

There are some properties for Menu component, that contains transitions. Such as enter and exit. You can find all properties here
I suppose you want to achieve transition of width and height from 0 to whatever it is. But it seems like Menu has preset width and heigh. So you need to implicitly set from and to properties for animations. For example:
Menu {
id: contextMenu
enter: Transition {
ParallelAnimation {
NumberAnimation { property: "height"; from: 0; to: contextMenu.implicitHeight; duration: 200 }
NumberAnimation { property: "width"; from: 0; to: contextMenu.implicitWidth; duration: 200 }
}
}
MenuItem { text: "Cut" }
MenuSeparator{}
MenuItem { text: "Copy" }
MenuItem { text: "Paste" }
}

Related

Is there a way to make unselectable a "list item" in ListView?

I am new to Qt. Wondering if there a possibility to make an item "unselectable" in ListView.
I see there are a lot of other things, e.g: collapsing , expanding, etc.
**
I have not find any simple example for this problem. **
Can you provide some minimalistic examples to make a specific item in the list unselectable?
I have the following minimalistic example. How can I set list item index 2 to be unselectable?
Window {
id: mainWindow
width: 130
height: 240
visible: truetitle: qsTr("Hello")
Rectangle {
id: bg
color: "#ffffff"
anchors.fill: parent
ListModel {
id: nameModel
ListElement { name: "Alice" }
ListElement { name: "Bob" }
ListElement { name: "Jay" }
ListElement { name: "Kate" }
}
Component {
id: nameDelegate
Text {
text: model.name
font.pixelSize: 24
}
}
ListView {
anchors.fill: parent
model: nameModel
delegate: nameDelegate
clip: true
highlight: Rectangle {
anchors { left: parent.left; right: parent.right }
//height: parent.height
color: "lightgrey"
}
}
}
}
I found numerous issues with your code snippet, so I attempted to address them all:
I made use of Page and set Page.background instead of declaring an outer Rectangle. This removes a level of indentation
I refactored NameComponent.qml to reduce the complexity of your main program
I change the delegate from Text to ItemDelegate so that it is clickable, and, it being clickable, I can (1) make the ListView have active focus so that it can receive keyboard events, (2) change the current item in the ListView => I think this achieves your criteria of being able to select a different item
I removed unnecessary anchoring from your highlight - your highlight will default anchor to your selected item
I set the width of your delegate to listView.width - I also made use of the ListView.view attached property so that your delegate and access properties from the ListView
Finally, I added a 20 pixel width vertical ScrollBar
import QtQuick
import QtQuick.Controls
Page {
background: Rectangle { color: "#ffffff" }
ListModel {
id: nameModel
ListElement { name: "Alice" }
ListElement { name: "Bob" }
ListElement { name: "Jay" }
ListElement { name: "Kate" }
}
ListView {
anchors.fill: parent
model: nameModel
delegate: NameDelegate { }
clip: true
highlight: Rectangle {
color: "lightgrey"
}
ScrollBar.vertical: ScrollBar {
width: 20
policy: ScrollBar.AlwaysOn
}
}
}
// NameDelegate.qml
import QtQuick
import QtQuick.Controls
ItemDelegate {
property ListView listView: ListView.view
width: listView.width - 20
text: model.name
font.pixelSize: 24
onClicked: {
listView.forceActiveFocus();
if (listView.currentIndex === index) {
listView.currentIndex = -1;
} else {
listView.currentIndex = index;
}
}
}
You can Try it Online!

Displaced ViewTransition not triggered in QML

So I have a ListView and ListModel to which I'm adding objects dynamically. I want a displaced animation to happen to when a new object is added, but from what I can see, only the add transition is triggered and the displaced transition is never triggered. Based on the tutorial, this works:
Rectangle {
anchors.fill: parent
ListView {
width: 240; height: 320
model: ListModel {
id: model
}
Component {
id: del
Row {
height: 20
spacing: 20
Text { text: name }
Text { text: age }
}
}
delegate: del
add: Transition {
NumberAnimation { property: "opacity"; from: 0; to: 1.0; duration: 1000 }
}
displaced: Transition {
NumberAnimation { properties: "x,y"; duration: 1000; easing.type: Easing.OutBounce }
}
focus: true
Keys.onSpacePressed: model.insert(0, { "name": "Item " + model.count, "age":21})
}
}
But this only triggers the add transition.
Rectangle {
height: 500
width: 0.90 * parent.width
anchors {
top: parent
topMargin: 30
left: parent.left
leftMargin: 45
}
ListView {
anchors.fill: parent
model: notificationModel
delegate: notificationDelegate
spacing: 30
add: Transition {
NumberAnimation { property: "opacity"; from: 0; to: 1; duration: 1000 }
}
displaced: Transition {
NumberAnimation { properties: "x,y"; duration: 1000; easing.type: Easing.OutBounce }
}
}
}
ListModel {
id: notificationModel
Component.onCompleted: {
notificationModel.append({"name": "Tony"})
}
}
Timer {
interval: 5000; running: true; repeat: true
onTriggered: notificationModel.append({"name": "Stark"})
}
Component {
id: notificationDelegate
Row {
spacing: 20
Text { text: name; color: "white" }
}
}
Any idea why this happens? Thanks!
The displaced transition is triggered when an item in the list is forced to move because another item is added/removed/etc. The working example works because a single item gets inserted at the beginning of the list causing the remaining items to be displaced.
With the current code you are showing, the problem is that you are using the append function instead of insert. Append adds items to the bottom of the list, so no items are getting displaced.
Before you edited your question, you had a different problem. You were using insert to add items to the beginning of the list, but every time you added one, you were clearing the entire list and rebuilding it. So again, nothing was getting displaced because the entire list was getting recreated every time.

How to animate adding and removing element to Layout in QML?

I want to animate adding and removing of TextField in ColumnLayout. Basically I want to animate like this:- https://doc.qt.io/qt-5/videos/viewtransitions-basic.mp4
As a ColumnLayout uses the implicitHeight to position the items, you can add an animation to that to create the sliding effect. I used a wrapping Item to preserve the implicitHeight of the TextField itself. It may not look perfect, but I don't think you cannot get that much further
Item {
visible: your_property_here
implicitHeight: visible ? text.implicitHeight : 0
Behavior on implicitHeight { NumberAnimation { duration: 500 } }
TextField {
id: text
anchors.fill: parent
scale: parent.visible ? 1 : 0.2
Behavior on scale { NumberAnimation { duration: 500 } }
}
}
I didn't found effective answer. Until then I'm using column as workaround
import QtQuick
import QtQuick.Layouts
import QtQuick.Controls
Page {
id: page_root
component ETextField : TextField {
width: root.width/2
}
state: "LOGIN"
Column {
anchors.centerIn: parent
ETextField {
id:host
placeholderText: "Host e.g:- exam.server.com:8080"
}
ETextField {
id:uane
placeholderText: "Username"
}
ETextField {
id: passwd
placeholderText: "Password"
}
ETextField {
id: confirm_passwd
placeholderText: "Confirm Password"
}
RowLayout {
Button {
id: submit
text: "Login"
}
Button {
id: change_state
text: "Register Instead"
onClicked: page_root.state = page_root.state === "LOGIN" ? "REGISTER" : "LOGIN"
}
}
}
states: [
State {
name: "LOGIN"
PropertyChanges {
target: confirm_passwd
height: passwd.height
}
PropertyChanges {
target: change_state
text : "Register Instead"
}
},
State {
name: "REGISTER"
PropertyChanges {
target: confirm_passwd
height: 0
}
PropertyChanges {
target: change_state
text : "Login Instead"
}
}
]
transitions: [
Transition {
from: "LOGIN"
to: "REGISTER"
NumberAnimation {
target: confirm_passwd
property : "height"
duration: 100
}
},
Transition {
from: "REGISTER"
to: "LOGIN"
NumberAnimation {
target: confirm_passwd
property : "height"
duration: 100
}
}
]
}

How Can I implement an transition when change tab in tabview?

I'm trying to find any way to implement an transition when i navigate between tabs in an TabView in QML, but I can't find that, is there any way to do it ?
my code is:
TabView{
id : tbView
height: parent.height
width: parent.width
Tab{
HomePage{
id: home
height: tbView.height
width: tbView.width
onBtnConfigClicked: btnPlay()
}
}
Tab{
Rectangle{
anchors.fill: parent
color: "blue"
}
}
}
function btnPlay()
{
tbView.currentIndex = 1
}
the HomePage element has an signal btnConfigClick, then i attach it to the function btnPlay, it function change currentIndex property to 1, the first tab is 0, I would like an slide transition when a change the currentIndex.
Well, you can use the TabBar compontent together with a SwipeView:
From documentation:
TabBar {
id: bar
width: parent.width
TabButton {
text: qsTr("Home")
}
TabButton {
text: qsTr("Discover")
}
TabButton {
text: qsTr("Activity")
}
}
SwipeView {
width: parent.width
currentIndex: bar.currentIndex
Item {
id: homeTab
}
Item {
id: discoverTab
}
Item {
id: activityTab
}
}
So changing the currentIndex property of TabBar will automatically perform a SwipeView transition to corresponding item.
Because your question is not entirely clear to me, I do not know whether that is what you wanted to achieve.

QML StackView custom transition

I have gone through the Qt docs :Qt StackView yet still I can't figure out what am I doing wrong, because my code should produce fade in/out animation but what I got is just an instant blink between content. I hope my description is sufficient and clear.
StackView {
id: stackView
anchors.fill: parent
delegate: StackViewDelegate {
function transitionFinished(properties)
{
properties.exitItem.opacity = 1
}
property Component pushTransition: StackViewTransition {
PropertyAnimation {
target: enterItem
property: "opacity"
from: 0
to: 1
duration: 10
}
PropertyAnimation {
target: exitItem
property: "opacity"
from: 1
to: 0
duration: 10
}
}
}
initialItem: Item {
width: parent.width
height: parent.height
ListView {
model: pageModel
anchors.fill: parent
delegate: AndroidDelegate {
text: title
onClicked: stackView.push(Qt.resolvedUrl(page))
}
}
}
}
I hit the same problem and asked their support - their example is wrong.
replace
property Component pushTransition: StackViewTransition {
with
pushTransition: StackViewTransition {
and it should work. pushTransition is actually a property on StackViewDelegate
I'm still trying to get the transitionFinished function to work becuase their example of that doesn't work either.
The duration of your animation is 10 milliseconds, or 1/100th of a second.
This is working for me:
Window {
id: mainWindowId
width: 1280
height: 800
StackView {
id: stackViewId
anchors.fill: parent
replaceEnter: Transition {
PropertyAnimation{
property: "opacity"
from: 0
to: 1
duration: 300
}
}
replaceExit: Transition {
PropertyAnimation{
property: "opacity"
from: 1
to: 0
duration: 250
}
}
initialItem: "yourStartingPage.qml"
}
}
And for changing views:
stackViewId.replace("yourOtherPage.qml")

Resources