I'm making an application with Qt and QML ( version 5.10 ) and using Qt.QuickControl 1.5.
I'm facing a problem with the StackView Transition:
Whenever I push an Item I make a simple Sliding Transition, the enterItem slides in and the exitItem slides out.
StackView {
id: stackView
anchors.fill: parent
focus: true
delegate: StackViewDelegate {
pushTransition: StackViewTransition {
PropertyAnimation {
target: exitItem
property: "x"
from: 0
to: exitItem.width
}
PropertyAnimation {
target: enterItem
property: "x"
from: -enterItem.width
to: 0
}
}
}
}
It's really simple. The problem is that when I push an Object in the StackView the transition is not happening. BUT when I pop the Transition I see the transition.
I create the objects for the StackView dynamically like
stackView.push(Qt.createComponent(_someurl_).createObject());
I cannot understand what the problem is.
Related
I have an item that consists of an image:
Item {
/* other stuff */
Image {
id: img
anchors.fill: parent
source: mySource
asynchronous: true
fillMode: Image.PreserveAspectFit
}
}
I want to overlay a (transparent) rectangle of the same size on the image when one hovers over it, so that I can do stuff like provide captions for the image etc.
How would one go about doing this?
My first try below: (I used console statements to verify that hovering on an image itself works)
import QtQuick 2.6
Item {
Image {
id: img
anchors.fill: parent
source: mySource
asynchronous: true
fillMode: Image.PreserveAspectFit
MouseArea {
enabled: img.status == Image.Ready
anchors.fill: parent
hoverEnabled: true
onEntered: {
console.log("Entering: ")
overlay
}
onExited: {
console.log("Exiting: ")
}
}
Rectangle {
id : overlay
anchors.fill: parent
color: "transparent"
Text {
id: imgcaption
text: "Caption"
anchors.bottom: overlay.bottom; anchors.verticalCenter: overlay.verticalCenter
font.pointSize : 14
}
}
}
}
When I do this I get something like this at all times, regardless of if I'm hovering over the image or not.
I also tried to put the Rectangle inside the onEntered handler itself, but when I do this the image doesn't display at all, and neither do the console statements so I'm not sure if this is valid QML.
It should be fairly obvious that I'm new to QML and don't really know what I'm doing, so I'd appreciate it if someone could point me in the right direction.
Try toggling the visibility based on the containsMouse property, like this:
Item {
Image {
id: img
anchors.fill: parent
source: mySource
asynchronous: true
fillMode: Image.PreserveAspectFit
MouseArea {
id: mouseArea
enabled: img.status == Image.Ready
anchors.fill: parent
hoverEnabled: true
}
Item {
id : overlay
anchors.fill: parent
visible: mouseArea.containsMouse
Text {
id: imgcaption
text: "Caption"
anchors.bottom: overlay.bottom; anchors.verticalCenter: overlay.verticalCenter
font.pointSize : 14
}
}
}
}
HoverHandler might be better. It's born to deal with hover events so you don't have to set hoverEnabled or anchors.
More importantly, it's transparent for mouse movement. This would be useful in more tricky scenarios, such as dealing with hover events for an item that already contains interactive controls (Button, Flickable, MouseArea, etc).
If you still use MouseArea in such cases, it may interrupt how these controls deal with hover events while HoverHandler won't. (MouseArea has a propagateComposedEvents property, which only controls whether clicked, doubleClicked, and pressAndHold would be propagated or not.)
Facing some issue using QML Animatiors in state Transition animations. Here is my working sample Code. In this sample if I decide not to provide "from" Attribute for the OpacityAnimator( reason is i wanted it to consider the current property value) the animator is not animating the property.
import QtQuick 2.12
import QtQuick.Controls 2.12
import QtQuick.Layouts 1.12
import QtQuick.Window 2.12
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
property bool isOpen: false
Button {
anchors.centerIn: parent
text: "Fade Animation Open Layer "
onClicked: {
isOpen = true;
overlay.state = "open";
}
}
Rectangle {
id: overlay
anchors.fill: parent
color: "green"
visible: isOpen
opacity: 0
Button {
anchors.centerIn: parent
text: "Close Overlay"
onClicked: {
overlay.state = "close"
}
}
state: "close"
states: [
State {
name: "hidden"
},
State {
name: "visible"
}
]
transitions: [
Transition {
from: "close"
to: "open"
OpacityAnimator {
target: overlay
from: 0.0
to: 1.0
duration: 600
easing.type: Easing.OutCubic
}
},
Transition {
from: "open"
to: "close"
SequentialAnimation {
OpacityAnimator {
target: overlay
//from: overlay.opacity
to: 0.0
duration: 600
easing.type: Easing.OutCubic
}
ScriptAction {
script: {
isOpen = false;
}
}
}
}
]
}
}
If i use PropertyAnimation instead, the fade effect works absolutely fine. So I just digged in to the Animator Code to and found out the below snippet from the apply function of qquickanimator.cpp and assume it means if "from" not specified it is supposed to fetch it from the target's property value and a comment Claims the magic line works like PropertyAnimation. But it is not working this way
if (isFromDefined)
job->setFrom(from);
else if (action.fromValue.isValid())
job->setFrom(action.fromValue.toReal());
else
job->setFrom(action.property.read().toReal());
// This magic line is in sync with what PropertyAnimation does
// and prevents the animation to end up in the "completeList"
// which forces action.toValue to be written directly to
// the item when a transition is cancelled.
action.fromValue = action.toValue;
So my Questions are:
Is it a Bug in the Qt Animator or am I missing something here?
Is it ok to combine PropertyAnimation and Animators(Opacity,Scale) in a Grouped animation(Sequential or Parallel) for a state Transition provided Animators scope is Scene graph and for PropertyAnimation it's the target object
See this comment in the documentation for the from property of Animator:
If the Animator is defined within a Transition or Behavior, this value defaults to the value defined in the starting state of the Transition, or the current value of the property at the moment the Behavior is triggered.
I think this means it will use the to value of 1.0 from the open state instead of the current value on the target. Seems like the state machinery is tracking and using how the transitions left things instead of current values.
Your from: overlay.opacity should workaround that behavior?
Hopefully I'm not missing something obvious here.
I am writing an app and have made a zoom in button with an Image and a MouseArea. I need the button to repeat a method call after, say, every second to zoom in while holding the mouse button down. It isn't entirely obvious how to make this repeat. Right now I have:
Rectangle {
id:zoomInBtn
Image {
id: zoomInImg
anchors.centerIn: parent
fillMode: Image.PreserveAspectFit
source: zoomIn.pressed ? ":/img/zoom_in_sel" : ":/img/zoom_in_unsel"
}
MouseArea {
id: zoomIn
anchors.fill: parent
onPressed: { cameraController.zoomIn(0.5); }
}
I have also tried with
onPressAndHold: { cameraController.zoomIn(0.5); }
which does basically the same, although with a small delay as expected, but I need to repeat this action every second while the mouse button is held.
To perform the task you need you must use a Timer. the timer must remain active while the containsMouse is active. you must also enable triggeredOnStart to run immediately if the timer is activated.
Rectangle {
id:zoomInBtn
Image {
id: zoomInImg
anchors.centerIn: parent
fillMode: Image.PreserveAspectFit
source: zoomIn.pressed ? ":/img/zoom_in_sel" : ":/img/zoom_in_unsel"
}
MouseArea {
id: zoomIn
anchors.fill: parent
}
Timer {
id: timer
interval: 1000
repeat: true
triggeredOnStart: true
running: zoomIn.containsMouse
onTriggered: cameraController.zoomIn(0.5) //task
}
}
}
I want to drag my custom buttons QML after a long press over them. I've implemented that behaviour, however the problem is that after enabling drag, I need to press button once again to actually start dragging. How should I implement this mechanism if I want to move buttons without releasing after long press?
Here is my button code (onReleased and onLongPressed are my own signals):
ButtonWidget.SoftButtonUI
{
id:softButtonDelegate2
x:500
y:300
labelText: "button"
iconImageSource: path
isGrayedOut: false
Drag.active: dragArea2.drag.active
Drag.hotSpot.x: 10
Drag.hotSpot.y: 10
onReleased:
{
console.log("onClicked")
}
onLongPressed:
{
console.log("onLongPressed")
dragArea2.enabled = true
}
MouseArea {
id: dragArea2
enabled: false
anchors.fill: parent
drag.target: parent
onReleased: parent.Drag.drop()
onClicked: {
console.log("MouseArea onClicked")
}
onPressAndHold: {
console.log("MouseArea onPressAndHold")
}
}
}
Any idea?
Generally speaking you can connect different signals and concatenate operations as discussed in this page. You should have a look at it since it is full of nice and useful information.
However, when it comes to mouse events, an interesting approach to events concatenation is given by MouseEvents acceptation. Documentation says about MouseEvent::accepted:
Setting accepted to true prevents the mouse event from being
propagated to items below this item. Generally, if the item acts on
the mouse event then it should be accepted so that items lower in the
stacking order do not also respond to the same event.
In this case we can take the opposite approach by not accepting the event. This way the pressed event can be used to both activate the drag and actually perform it. Then the MouseEvent can be accepted (implicitly) in the release event, occurring at the end of the drag.
Here is a simple example following this approach. As the mouse is pressed and hold the drag.target is set and drag can start, whereas when the mouse is released the drag.target is removed, removing the dragging behaviour. To test it, just press and hold the mouse over the rectangle and when it changes color just drag it.
import QtQuick 2.4
import QtQuick.Controls 1.3
ApplicationWindow {
width: 300
height: 300
visible: true
Rectangle {
id: item
border.width: 2
x: 100
y: 100
width: 100
height: 100
state: "BASE"
states: [
State {
name: "BASE"
PropertyChanges { target: mouseArea; drag.target: undefined}
PropertyChanges { target: item; color: "steelblue"}
},
State {
name: "DRAGGABLE"
PropertyChanges { target: mouseArea; drag.target: item}
PropertyChanges { target: item; color: "darkblue"}
}
]
MouseArea {
id: mouseArea
anchors.fill: parent
drag{
// target: NOT SET HERE
minimumX: 0
minimumY: 0
maximumX: parent.parent.width - parent.width
maximumY: parent.parent.height - parent.height
smoothed: true
}
onPressAndHold: {
item.state = "DRAGGABLE"
mouse.accepted = false // mouse event is USED but NOT CONSUMED...
}
onReleased: {
item.state = "BASE" // mouse event acceptation occurs here!
}
}
}
}
This simple approach should work perfectly also with your custom signals.
I have 9:9 matrix of Rectangle elements on the main QML form with Repeater. What I want to implement is if user clicks on one of rectangles, it zooms to TextEdit widget which on Esc press zooms back.
Is it possible with QML?
If yes, how am I supposed to turn Rectangle to TextEdit and zoom this TextEdit to fill the parent?
Just starting to work with QML and can't quite get an answer from http://doc.qt.nokia.com/4.7-snapshot/qdeclarativeanimation.html yet.
Thank you.
1) Sure thing! This is more or less what QML is made for.
2) This is an example of how you can do what you want (not the only way to do it):
Rectangle {
id: parentRect
width: 500; height: 500
// Every item in the grid should look like this
Rectangle {
id: singleItem
color: "red"
state: "closed"
// Hidden text input, shown when user clicks
TextInput {
id: textInput
anchors.fill: parent
text: "Input here"
cursorVisible: true
}
// MouseArea that will catch the user click
MouseArea {
anchors.fill: parent
onClicked: singleItem.state = "open"
}
// Item states
states: [
State {
name: "closed"
PropertyChanges {target: singleItem; width: 25; height: 25}
PropertyChanges {target: textInput; opacity: 0}
},
State {
name: "open"
PropertyChanges {target: singleItem; width: parentRect.width; height: parentRect.height}
PropertyChanges {target: textInput; opacity: 1; focus: true}
}
]
// Transitions between states
transitions: Transition {
ParallelAnimation {
NumberAnimation {
target: singleItem
properties: "width,height"
duration: 1000
}
NumberAnimation {
target: textInput
property: "opacity"
duration: 1000
}
}
}
}
}
Even I'm new to qt-quick. I don't think it is possible to zoom unless we write our code to do such. I'm not sure though. :-)
This effect is good and it will b nice to see in coming versions. Try to give a feature request to the community <3