QML animations and effects - qt

imagine that we have arrow image as here:
but we want to make from this image an animation:
question
This not very elegant animation was created from a set of different arrow images.
But i want to make same animation by qml. Do you know any components(preferably qml but if you do not know, you can advise me qt classes) with which help i can reach that?
And another question, does it make sense from the point of view of performance to search any ways to reach that instead of combine set of images to gif-format?

Updating based on new information that the arrow has a background.
You need to crop out the arrow to an image file with a transparent background and have the background as a separate image.
From there, you can use a similar concept as below, but with the arrow growing. I believe you will be able to find an image mode that fits the image vertically and does not manipulate it horizontally. I would start by trying fillMode: Image.TileHorizontally.
Treat this as pseudo code, I don't have access to a computer to run this on at the moment.
Image
{
id: backgroundImage
source: "background.png"
Image
{
id: arrowWithTransparentBackground
fillMode: Image.TileHorizontally
source: "arrow.png"
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
SequentialAnimation on width {
loops: Animation.Infinite
PropertyAnimation { from 0: to: parent.width }
}
}
}
Old answer for reference, before knowing there was a background to the image:
QML very nicely animates size changes. You could easily have a rectangle on top of your image anchored to the left side that is white and grows from 0 to arrow.width.
Treat this as pseudo code, I don't have access to a computer to run this on at the moment.
Image
{
id: arrowImage
source: "arrow.png"
Rectangle
{
color: "white"
anchors.left: parent.left
anchors.top: parent.top
anchors.bottom: parent.bottom
SequentialAnimation on width {
loops: Animation.Infinite
PropertyAnimation { from 0: to: parent.width }
}
}
}

Related

Proper way of defining and composing custom elements in QML

Lets say I want to create a field element in QML which has its "field" part and could have icon on the right, left side or not show it at all. Basic qml code would look like this (without functionality to change sides):
// TestField.qml
Item
{
Image
{
anchors.right: field.left
anchors.top: field.top
source: "qrc:/res/settings/logOptions.svg"
height: 40
width: 40
}
Rectangle
{
id: field
anchors.fill: parent
color: "blue"
}
}
Then I will use it like this:
// Main.qml
TestField
{
x: 100
y: 100
height: 100
width: 100
}
Or use it in some grid layout, anchor it to another element, etc. I used hardcoded coordinates and sizes just to keep the question simpler.
The problem with this is that I specified sizes for the element (100x100) and my field rectangle would fill the whole space, leaving icon "hanging" out of bounds of this element. In this case QML will treat this element as of the size 100x100, but since the icon is out of bounds the actual size of the whole element with the icon is bigger (140x100) and could overlap with other such elements when placed into layout.
Worth noting that for such elements I want to be able to change position of the icon to be to the left or right of the rectangle (it will be some sort of property with enum value, that I will define in code, it won't change dynamically throughout application work) so some rectangles will have icon from different sides.
One solution I see is to rework TestField so its elements will be tied to parents width or height, for example:
Item
{
Image
{
x: 0
y: 0
width: parent.width / 2
height: parent.width / 2
}
Rectangle
{
id: field
x: parent.width / 2
y: 0
width: parent.width / 2
height: parent.height
}
}
The question is - is this a good solutions or there are proper ways to tackle such issue? My main concern is that element size should be actually the size that I could query with element.width or element.height and none of the internal part are out of bounds possibly overlapping with other elements. Maybe I'm missing some basic concept that will allow me to make elements that always keep their parts inside its bounds?
The problem with your sizing is that your Rectangle takes up the whole size of its parent. You want to shrink that to account for the size of the Image. I also added a way to switch the image between left and right side.
Item
{
property bool imageOnLeft: true
Image
{
id: img
anchors.left: imageOnLeft ? parent.left : field.right
source: "qrc:/res/settings/logOptions.svg"
height: 40
width: 40
}
Rectangle
{
id: field
anchors.left: imageOnLeft ? img.right : parent.left
width: parent.width - img.width
height: parent.height
color: "blue"
}
}

Framing VideoOutput item in Qt QML

I am using a VideoOutput item, which I have placed inside a Rectangle. This VideoOutput goes on top of the Rectangle, of its border and its rounded corners.
Rectangle{
radius: 12
width: 200
height: width
border.color: black
border.width: 15
VideoOutput {
fillMode: VideoOutput.PreserveAspectCrop
anchors.fill: parent
source: myCamera
autoOrientation: true
}
}
Camera {
id: myCamera
focus {
focusMode: CameraFocus.FocusContinuous
focusPointMode: CameraFocus.FocusPointAuto
}
captureMode: Camera.CaptureViewfinder
}
I intentionaly made the border thick so it really shows what is going on. The border is hidden by the VideoOutput, and the rounded corners are ignored.
I can imagine that the VideoOutput item would use some acceleration tricks, so it might not play well with standard QML item behaviour. But is there a way get this to work, without adding a filter element, or is this the expected behaviour?

QML: What does the "x" property exactly do and what's the difference with anchors.leftMargin/rightMargin in a ListView?

I tried to add a margin to a ListView element using anchors.leftMargin expecting it would create a margin between the screen border and the beginning of the list, but it didn't work at all. Using x instead solved the problem. Here is the code:
ListView {
id: list
width: parent.width - sideMargin
x: sideMargin //works
anchors.leftMargin: sideMargin //doesn't work
orientation: ListView.Horizontal
focus: true
spacing: 16
//...
}
So now I am wondering when to use these properties, because reading the docs is not enough for me to understand when to use one or the other.
Items in QML/QtQuick can be positioned and sized in 3 different ways:
Freely using the x and y properties for position and the width and height properties for the size.
See: https://doc.qt.io/qt-5/qml-qtquick-item.html#x-prop for more information.
ListView {
id: list
width: parent.width - sideMargin
x: sideMargin
y: topMargin
}
Using Layouts, or more generally containers, such as ColumnLayout. All the work is done by the layout and you don't have to do anything, but you can still provide tips to the container.
Using anchors. This is done through the anchors properties of each Item. This works by attaching (anchoring) Items against each other.
ListView {
id: list
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: sideMargin
}
Note: Do not mix these 3 ways on a single Item as you can create conflicts or have unexpected results. In your case you are using method 3 for setting the margin without setting a position and method 1 for setting the width and thus it does not work.

QML: button with image and text underneath

I am trying to create a button like control in QML which displays an image and also some text under it. My current attempt stands as follows:
Item {
id: button
width: 30
height: 100
property alias text: buttontext
signal clicked
Image {
id: visualImage
anchors.fill: parent
source: "qrc:/images/test.png"
}
Text {
id: buttontext
font.bold: true
text: "Test"
}
}
This has a lot of problems unfortunately. So, at the moment, I am specifying the width and height of the item but this should be calculated based on the width and height of the image and the text. Also, the text is shown at the top and inside the image where I would like to position the text under the image, centered with image horizontally with some margins.
You must use anchors in the Image and in the Text. Example:
Item {
id: button
width: 30
height: 100
property alias text: buttontext
signal clicked
Image {
id: visualImage
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: buttontext.top
source: "qrc:/images/test.png"
}
Text {
id: buttontext
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
font.bold: true
text: "Test"
}
}
Since QtQuick.Controls 2.3 (Qt 5.10), display property was introduced:
This property determines how the icon and text are displayed within the button.
For your case it's AbstractButton.TextUnderIcon
Something I have done in the past as a workaround for this,
create a Rectangle{……} which holds all the 'Button' items, (Text/Image Ect),
It may not be the prettiest way but there is a few variations
Create the 'Image' and 'text' externally (photoshop whatever you choose) then fill your Rectangle with the content, then also set a MouseArea { onClicked {……}} event to that,
Make a Column/Grid/Row within the Rectangle and position your items using that method

How to correctly change the row height of a TableView?

Window {
id: uninstallWindow
width: 640
height: 480
property variant pluginData;
TableView {
id:_pluginTable
anchors.right: parent.right
anchors.rightMargin: 0
anchors.left: parent.left
anchors.leftMargin: 0
anchors.bottom: parent.bottom
anchors.bottomMargin: 43
anchors.top: parent.top
anchors.topMargin: 0
model: pluginData
itemDelegate: Text {
text: modelData
font.pixelSize: 24
}
TableViewColumn {
}
}
}
It's taken me hours just to get this far, and I feel like this should be a relatively simple operation, so why is it so hard? As you can see I change the font size of the items in the table because they were too small by default. This simply caused them to get clipped by the non-changing row size. I've tried
Setting a rowDelegate object (but this causes loss of all other styling info that is there by default like background, selection color, etc and I don't know how to specify it otherwise)
Setting a custom model object based on QAbstractListModel / QAbstractTableModel (for some reason only known to Qt, the "data" function was never ever called...)
Setting a custom item delegate (it seems that the height is no longer controlled from this object though)
What hoops do I need to jump through to get the rows to change their size?
As the Asker already wrote, custom row height can be achieved using the rowDelegate, but this discards the default style. The default style can be restored using the SystemPalette.
rowDelegate: Rectangle {
height: 30
SystemPalette {
id: myPalette;
colorGroup: SystemPalette.Active
}
color: {
var baseColor = styleData.alternate?myPalette.alternateBase:myPalette.base
return styleData.selected?myPalette.highlight:baseColor
}
}
This restores the default background color of the rows (including alternating the row colors when desired) and the color of the selected rows, which seems to be all that is needed.
The following just worked like a charm for me in Qt 5.10:
rowDelegate: Item { height: 30 }
I do the actual styling (fonts/colors) in itemDelegate (and in headerDelegate) and provide content by TableViewColumns (with and without delegates of their own).
To change the row height you need to use rowDelegate. For example:
rowDelegate: Rectangle{
width: childrenRect.width
height: 40
}
To change tableview height you can use Layout.preferredHeight. For example:
Layout.preferredHeight: 300

Resources