How can I animate a Dialog to enter from outside the screen? - qml

This question is similar to - but no the same as Moving qml Item out of left side of window, because my question is about Dialogs, instead of Items in general. The difference is explained below.
I have a Qt Dialog which I want to enter the screen from the left.
The first approach I took was setting the dialogs x property to -width and then adding a Behavior on x or a manually triggered NumberAnimation.
This approach however failed, because setting negative x values is not allowed and the value gets changed to 0 immediately.
This post provides a solution for this issue, by using anchors and AnchorChanges and transitions - but only for Items.
However, the Dialog type does neither provide states, nor anchors but only coordinates.
So my question stands: How can I have a QML Dialog animate from the left outside the screen into view?
Here's a minimal code sample, that demonstrate the x property being reset to 0:
import QtQuick 2.7
import QtQuick.Controls 2.3
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Dialog Demo")
Dialog {
id: dialog
width: 200
height: 200
x: -width
Text {
anchors.centerIn: parent
text: "Ok?"
}
standardButtons: Dialog.Ok
onOpened: x = 100
Behavior on x { NumberAnimation{ duration: 1000 } }
}
Component.onCompleted: dialog.open()
}

You can use the enter-transition that is inherited from Popup:
import QtQuick 2.9
import QtQuick.Window 2.0
import QtQuick.Controls 2.3
Window {
id: window
visible: true
width: 600
height: 600
Dialog {
id: dialog
width: 300
height: 300
enter: Transition {
NumberAnimation { properties: "x,y"; from: -300; to: 150 }
}
}
Button {
anchors.centerIn: parent
onClicked: dialog.open()
}
}
There seems to be a Bug with the Dialog. As soon as the Dialog has some content, it fails. I have not discovered all depths of it, but wrapping everything in an Item seems to help. Compare for this:
import QtQuick 2.9
import QtQuick.Window 2.0
import QtQuick.Controls 2.3
ApplicationWindow {
id: window
visible: true
width: 600
height: 600
Dialog {
id: dialog
width: 300
height: 300
enter: Transition {
NumberAnimation { properties: "x,y"; from: -300; to: 150; duration: 5000 }
}
// HAVE A BUTTON IN THE DIALOG -> POSITIONING FAILS
Button {
anchors.centerIn: parent
}
}
Button {
text: 'open'
anchors.centerIn: parent
onClicked: dialog.open()
}
}
and
import QtQuick 2.9
import QtQuick.Window 2.0
import QtQuick.Controls 2.3
ApplicationWindow {
id: window
visible: true
width: 600
height: 600
Dialog {
id: dialog
width: 300
height: 300
enter: Transition {
NumberAnimation { properties: "x,y"; from: -300; to: 150; duration: 5000 }
}
Item { // WRAP IT IN THE ITEM -> WORKS FOR ME
anchors.fill: parent
Button {
anchors.centerIn: parent
}
}
}
Button {
text: 'open'
anchors.centerIn: parent
onClicked: dialog.open()
}
}

Related

transferring the same images logic to another file

Is it possible to transfer the same code logic in another page, in which these two images are taken as alias or something similar and they behave in the same pattern of "if statement" logic on the other QML file(2) when this button is pressed from the first QML file(1)?
import QtQuick 2.15
import QtQuick.Controls 2.15
import QtQuick.Studio.Components 1.0
import QtQuick.Timeline 1.0
Item {
id: root
width: 500
height: 500
property alias locking: locking
Text {
id: confirmSign
text: qsTr("")
anchors.left: parent.left
anchors.top: parent.top
font.styleName: "Bold"
anchors.leftMargin: 70
anchors.topMargin: 55
color: "white"
font.pointSize: 10
font.family: "Tahoma"
}
RoundButton {
id: locking
y: 70
width: 90
height: 90
anchors.left: password_field.right
anchors.leftMargin: 15
Image {
id: unlck
anchors.centerIn: parent
source: "Images/Unlocked.png"
visible: false
}
Image {
id: lcked
anchors.centerIn: parent
source: "Images/Locked.png"
visible: true
}
onClicked: {
passBlocker.visible = true
confirmSign.text = qsTr("The ToolBar is 'Locked' ");
confirmSign.color = "#ffffff";
lcked.visible = true
unlck.visible = false
}
}
}
You can create a new file just for the lock image and use it wherever you want.
Something like this:
File LockImage.qml
Item {
property bool locked: false
Image {
id: lcked
anchors.centerIn: parent
source: locked? "Images/Locked.png": "Images/Unlocked.png"
visible: true
}
}
Side note: you don’t need to change properties using clicked handler. Prefer using the checked property of Button

Opacity change on button hovered glitch QML

I have created a custom virtual keyboard where the components are buttons, whose attributes I have defined in the code below . When I rapidly move the mouse across the buttons, I find that there is a 'flashing' effect whereby the button opacity appears to momentarily drop to 0 and then return. How can I prevent this flashing effect?
import QtQuick 2.15
import QtQuick.Controls 2.12
import QtGraphicalEffects 1.0
import "definitions.js" as Defs
Button {
id: keyboardButton
property bool specialButton: false
contentItem: Text {
text: keyboardButton.text
font.family: Defs.font
font.pointSize: Defs.defaultTextSize
color: Defs.ivory
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
background: Rectangle {
id: background
property double op: specialButton ? 0.7 : 0.5
color: Defs.b_blue
opacity: op
radius: 0
OpacityAnimator on opacity{
running: keyboardButton.hovered
from: background.opacity
to: background.op + 0.05
duration: 100
}
OpacityAnimator on opacity{
running: !keyboardButton.hovered
from: background.op + 0.05
to: background.op
duration: 100
}
}
}
Using one animator fixes it for me:
import QtQuick 2.15
import QtQuick.Controls 2.15
ApplicationWindow {
width: 640
height: 480
visible: true
Flow {
anchors.fill: parent
Repeater {
model: 100
Button {
id: keyboardButton
property bool specialButton: false
contentItem: Text {
text: keyboardButton.text
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
background: Rectangle {
color: "steelblue"
opacity: hovered ? baseOpacity + 0.15 : baseOpacity
radius: 0
property double baseOpacity: keyboardButton.specialButton ? 0.7 : 0.5
Behavior on opacity {
OpacityAnimator {
duration: 100
}
}
}
}
}
}
}

QML Image size is ignored

I have a ToolButton in QML with an image with size 48x48 pixels:
ToolButton {
contentItem: Image {
source: "Icons/idea48.png"
}
}
if I set width and height nothing changes:
ToolButton {
contentItem: Image {
source: "Icons/idea48.png"
width: 5
height: 5
}
}
on the screen it is still 48x48.
And even adding fill Mode does not help:
ToolButton {
visible: scene.serviceMode
contentItem: Image {
source: "Icons/idea48.png"
width: 10
height: 10
fillMode: Image.Stretch
sourceSize: {
width: 48
height: 48
}
}
}
the sourceSize should be 48 to render image with high pixel density.
I also tried to put Image inside Item, but with no success:
ToolButton {
contentItem: Item {
width: 24
height: 24
Image {
source: "Icons/idea48.png"
fillMode: Image.Stretch
sourceSize: {
width: 48
height: 48
}
}
}
}
Qt Quick Controls 2.3 (Qt 5.10) adds built-in support for button icons. By default, different styles may request different icon sizes, according to their design guidelines, but you can easily override the icon size.
ToolButton {
icon.width: 24
icon.height: 24
icon.source: "Icons/idea48.png"
}
What comes to high-DPI support, consider providing #Nx versions like the Gallery example does: http://code.qt.io/cgit/qt/qtquickcontrols2.git/tree/examples/quickcontrols2/gallery/icons/gallery?h=5.10
Answer 1
Set the sourceSize of the Image in order to influence its implicitWidth and implicitHeight, which are used by the ToolButton to determine the size of the contentItem.
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
visible: true
width: 640
height: 480
header: ToolBar {
RowLayout {
anchors.fill: parent
ToolButton {
contentItem: Image {
source: "Icons/idea48.png"
sourceSize.width: 10
sourceSize.height: 10
fillMode: Image.Pad
}
}
}
}
}
Answer 2
Put the Image inside an Item so that the Image is not resized by the ToolButton and its dimensions remain exactly as specified by width and height.
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
visible: true
width: 640
height: 480
header: ToolBar {
RowLayout {
anchors.fill: parent
ToolButton {
contentItem: Item {
Image {
source: "Icons/idea48.png"
width: 10
height: 10
}
}
}
}
}
}
Answer 3
Force the size of the contentItem.
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
visible: true
width: 640
height: 480
header: ToolBar {
RowLayout {
anchors.fill: parent
ToolButton {
contentItem: Image {
source: "Icons/idea48.png"
}
Component.onCompleted: {
contentItem.width = 10
contentItem.height = 10
}
}
}
}
}

How to Connect two qml files?

I am making a music player application. i have a DownRect which has a slider and a playSection which has a button. this button has a audio. when button is clicked audio is played and i want the slider to set it's value by the audio duration. (the button is add dynamically from ButtonD.qml file). what i want to do is to connect DownRect's slider to playSection's button.
//DownRect.qml
Rectangle{
id: downRectangle
width: parent.width
height: parent.height
x:0
y:750
color: "#c62828"
smooth: true
Slider{
id: sliderDownRect
x: 300
y: 25
width: 650
from: 0
// to: play.duration
stepSize: 100
value: 0
Material.accent : Material.background
Material.foreground: Material.background
onValueChanged:{
}
}
}
and here is the ButtonD.qml file which i'd like to connect to DownRect.qml
//ButtonD.qml
Button{
id: buttonD
width:900
height: 46
flat: true
Audio{
id: playing
}
}
You make sure that the duration (and other relevant properties of Audio) are exposed in ButtonD.qml, e.g. by adding aliases like such:
Button {
id: buttonD
property alias duration: playing.duration
...
}
The same goes for the Slider's value.
Rectangle {
id: downRectangle
property alias duration: sliderDownRect.to
...
}
In the file that instantiates both, you use Binding-objects to create a bidirectional binding between the both. Those Binding-objects excell at working with dynamically instantiated objects.
Basically, if you'd include the files into one file, this should look something like this:
main.qml
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtMultimedia 5.5
ApplicationWindow {
id: myWindow
visible: true
width: 600
height: 600
color: 'white'
property Item dynamicallyCreatedItem
Button {
x: 102
text: 'create'
onClicked: {
dynamicallyCreatedItem = Qt.createComponent('AudioButton.qml').createObject(myWindow.contentItem)
}
}
DownRect {
y: 50
id: rect
}
Binding {
target: rect
property: 'maxValue'
value: dynamicallyCreatedItem ? dynamicallyCreatedItem.duration : 0
when: dynamicallyCreatedItem
}
Binding {
target: rect
property: 'value'
value: dynamicallyCreatedItem ? dynamicallyCreatedItem.position : 0
when: dynamicallyCreatedItem
}
}
AudioButton.qml
import QtQuick 2.0
import QtQuick.Controls 2.0
import QtMultimedia 5.5
Button {
id: audioButton
onClicked: audio.play()
property alias duration: audio.duration
property alias position: audio.position
Audio {
id: audio
source: 'airhorn.wav'
}
}
DownRect.qml
import QtQuick 2.0
import QtQuick.Controls 2.0
Rectangle {
id: rect
width: parent.width
height: 50
property alias value: slider.value
property alias maxValue: slider.to
Slider {
id: slider
anchors.fill: parent
}
}

How to properly bind values to 'from' and 'to', inside a NumberAnimation?

I want to create a horizontal scrolling text animation (enter at the right side, go through the screen, exit at the left side, repeat).
import QtQuick 2.4
import QtQuick.Window 2.2
Window {
id: root
visible: true
Rectangle {
id: scrollLine
anchors.fill: parent
color: "black"
Text {
id: scrollText
color: "white"
text: "This is a test"
font.pixelSize: parent.height * 0.5
anchors.verticalCenter: parent.verticalCenter
x: scrollLine.width
NumberAnimation on x {
id: scrollAnimation
from: scrollLine.width; to: -scrollText.width
duration: 5000
loops: Animation.Infinite
running: true
}
}
}
}
The problem is, that my text acts weird. Appears left side, scrolls left with two characters, repeat... Something is wrong at the binding
from: scrollLine.width; to: -scrollText.width,
but I have no idea what.
Ah, this is weird! :)
The first thing I can see is that this
x: scrollLine.width
does nothing. The NumberAnimation runs immediately, causing the x value of the Text to be set, so we can remove that code to make it easier to find the problem.
The next thing to do is to print out the widths of the items:
import QtQuick 2.4
import QtQuick.Window 2.2
Window {
id: root
visible: true
Rectangle {
id: scrollLine
anchors.fill: parent
color: "black"
onHeightChanged: print("rectangle height", height)
Text {
id: scrollText
color: "white"
text: "This is a test"
font.pixelSize: parent.height * 0.5
anchors.verticalCenter: parent.verticalCenter
onWidthChanged: print("text width", width)
NumberAnimation on x {
id: scrollAnimation
from: scrollLine.width
to: -scrollText.width
duration: 5000
loops: Animation.Infinite
running: true
}
}
}
}
That gives us:
qml: text width 72.078125
qml: rectangle height 160
qml: text width 443.734375
Ok, it's weird that the text size changes width, but... it indirectly depends on the size of the window, right? We set its font.pixelSize to parent.height * 0.5. It just so happens that the window size is determined after the Text gets its initial size. However, being a declarative language, you'd think this should work.
Let's check the from and to values of the animation:
onFromChanged: print("from", from)
onToChanged: print("to", to)
Now we get:
qml: from 0
qml: to 0
qml: text width 72.078125
qml: to -72.078125
qml: from 160
qml: rectangle height 160
qml: text width 443.734375
qml: to -443.734375
They are initially incorrect, sure, but they do eventually become correct. This smells like a bug. Let's double check by printing out the x position of the Text:
qml: x -0.576625
...
qml: x -71.4654609375
That's not right. It seems like a bug. I thought it was, too, but then I checked the documentation:
If the NumberAnimation 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.
You're not using a Behavior, although the syntax looks very similar. A bit more searching reveals the documentation for the on keyword:
The animation starts as soon as the rectangle is loaded, and will automatically be applied to its x and y values.
So, it's not a bug. You'll have to give the animation sensible from and to values somehow. One solution is to hard-code the values:
import QtQuick 2.4
import QtQuick.Window 2.2
Window {
id: root
width: 250
height: 250
visible: true
Rectangle {
id: scrollLine
anchors.fill: parent
color: "black"
Text {
id: scrollText
color: "white"
text: "This is a test"
font.pixelSize: parent.height * 0.5
anchors.verticalCenter: parent.verticalCenter
NumberAnimation on x {
id: scrollAnimation
from: root.width
to: -1000
duration: 5000
loops: Animation.Infinite
running: true
}
}
}
}
The best solution would probably be not to rely on the window's height for the font size, though. The default font size chosen by Qt is legible on all platforms that provide sensible DPI information, so you would be better off multiplying that by some factor:
import QtQuick 2.4
import QtQuick.Window 2.2
Window {
id: root
width: 250
height: 250
visible: true
Rectangle {
id: scrollLine
anchors.fill: parent
color: "black"
FontMetrics {
id: fontMetrics
}
Text {
id: scrollText
color: "white"
text: "This is a test"
font.pixelSize: fontMetrics.font.pixelSize * 8
anchors.verticalCenter: parent.verticalCenter
NumberAnimation on x {
id: scrollAnimation
from: root.width
to: -1000
duration: 5000
loops: Animation.Infinite
running: true
}
}
}
}
You code works as expected with a little modification. Instead of using font.pixelSize: parent.height*0.5, I used a fixed size point. Try this
import QtQuick 2.4
import QtQuick.Window 2.2
Window {
id: root
visible: true
Rectangle {
id: scrollLine
anchors.fill: parent
color: "black"
Text {
id: scrollText
color: "white"
text: "This is a test"
font.pixelSize: 150; //////// Changed this
anchors.verticalCenter: parent.verticalCenter
x: scrollLine.width
NumberAnimation on x {
id: scrollAnimation
from: scrollText.width; to: -scrollText.width
duration: 5000
loops: Animation.Infinite
running: true
}
}
}
}