Solved Some questions on a QML transformation project
-
When a click on the MouseArea occurs the signal clicked() in the root will be triggered by the code onClicked: root.clicked() in MouseArea body. Correct?
Yes, and because the root has 'clicked' signal it also has the correponding signal handler 'onClicked' automatically. Now we set the handler; it prints to the log output. When the mouse area is clicked the text is printed.
Here the parent of Y and S is X and Y and S are siblings. The parent of Z is Y but we can change its parent. (by?)
Yes. It's not usually necessary or reasonable to change a parent manually.
-
Thanks for your info.
-
Hi,
In the Transformation.qml file we have:
import QtQuick 2.8 Item { width: bg.width height: bg.height Image { id: bg source: "/background.png" } MouseArea { id: backgroundClicker anchors.fill: parent onClicked: { circle.x = 84 box.rotation = 0 triangle.rotation = 0 triangle.scale = 1.0 } } ... }
First the part
Item { width: bg.width height: bg.height
seems useless because if I remove these and make the Image as the first item, the program runs with no changes. So what need is there for that please?
Neither id: bg nor id: backgroundClicker in the code seems to be needed as well.
Also I modified the main.qml code to:
import QtQuick 2.8 import QtQuick.Window 2.2 import QtQuick.Controls 2.0 import QtQuick.Controls.Styles 1.4 Window { visible: true width: 700 height: 600 title: qsTr("Transformation") Column { spacing: 20 Transformation { id: transformation } Button{ Text: "test_overlap" style: ButtonStyle onClicked: transformation._test_overlap() } Button { Text: "test_transformed" style: ButtonStyle onClicked: transformation._test_transformed() } Button { // Text: "Quit" onClicked: close() } } }
Using only
Transformation { id: transformation }
the program runs through a process, but what are its steps briefly, please?
I also tried to add a text and style to the buttons declared above. But got errors! -
width: bg.width
height: bg.height
seems uselessIn this case they may be useless and in general when you write a component (a qml file) you shouldn't explicitly give the top level item's height & width. It's a good habit to give implicit size instead. Unfortunately those things are a bit complicated but in short, width and height may be calculated by the engine and may differ from what you explicitly give. Implicit width and height are some sensible size which the visible component could have if it's not for example stretched to fill available space or if there is no explicit size given.
IDs are necessary only if the object must be known by name somewhere, but it may still be good for self-documentation. Come up with a descriptive name for an object and you may thank yourself later when you read your own code because you will know without further thinking why you have made the object.
import QtQuick.Controls 2.0
means that Controls 2 are used, not Controls 1. Change it to
import QtQuick.Controls 1.4
and you can use styles. I think that the qmlbook uses only Controls 1. I tend to use Controls 2.
Button{ Text: "test_overlap"
must be
Button{ text: "test_overlap" // property names must always begin with lower case, Text is a type name!
-
@Eeli-K
Thank you.you shouldn't explicitly give the top level item's height & width.
Did you mean "the top level item height & width", please?
IDs are necessary only if the object must be known by name somewhere, but it may still be good for self-documentation. Come up with a descriptive name for an object and you may thank yourself later when you read your own code because you will know without further thinking why you have made the object.
Yes, you're right. Thanks.
import QtQuick.Controls 2.0
means that Controls 2 are used, not Controls 1. Change it to
import QtQuick.Controls 1.4
What does it mean please, I can't understand well. Isn't Controls 2 used? Where is it stated?
// property names must always begin with lower case, Text is a type name!
Good info.
And when I use that style for the buttons, they won't be appeared on output! -
Did you mean "the top level item height & width", please?
I was a bit unclear. When you write a component (i.e. a qml file which can be used from other qml files) you've got the top level item first. For that item you can give implicitWidth/Height if there are reasonable default values for the size of that component. But you shouldn't give width/height properties explicitly.
//MyItem.qml import QtQuick...//whatever you need to import Item{ // top level item, rectangle, button or whatever id: control //width: 100 No! implicitWidth: 100 // Yes Rectangle{ // inner items go here }
When you use that component in another file you can there give w/h explicitly.
//main.qml ... MyItem { width: 150 //yes }
In many situations it doesn't matter whether you give explicit or implicit size and where you give it. In some situations it matters. It's better to use implicit in components themselves and explicit when you instantiate a component. However, look at what is done in the Material theme's Button.qml in Components 2:
T.Button { id: control implicitWidth: Math.max(background ? background.implicitWidth : 0, contentItem.implicitWidth + leftPadding + rightPadding) implicitHeight: Math.max(background ? background.implicitHeight : 0, contentItem.implicitHeight + topPadding + bottomPadding) ... contentItem: Text { ... } background: Rectangle { implicitWidth: 64 implicitHeight: 48 ... width: parent.width height: parent.height - 12 ... } ... }
The background rectangle has both implicit and explicit size! The control itself has only implicit size which is max of background's implicit size and contentItem's implicit size (which is the text's size by default). When you instantiate the Button and don't give explicit size the implicit size is used. The engine gives the actual width and height values based on implicit size. The background will get the same size which by default will be the same as control's implicit size. If, on the other hand, the developer gives explicit size (width&height) when the Button is instantiated, implicit size of the control is bypassed and both the component itself and the background will get that explicit size. The Text element will be elided if the explicit width is smaller than text's implicit width.
-
What does it mean please, I can't understand well. Isn't Controls 2 used? Where is it stated?
There are two sets of UI controls in Qt Quick, Controls 1 and Controls 2. Usually only one of them is selected for a given application, although they can be used together. Under the hood they work differently and they have different look&feel. You must import the one you are using (or both if you are using both in the same component). In Qt 5.9 the version of Controls 1 is 1.4 and the version of Controls 2 is 2.2. You can import an older version (at least for Controls 2), too, if you don't use features which require a newer version.
I used Button from Controls 2. Both Controls 2 and Controls 1 have a type named Button which both have a property named text. Therefore a simple button works if you change the import statement from version 1.4 to 2.2 or vice versa. However, only Controls 1 use the 'style' property for styling. Therefore it didn't work when only Controls 2 was imported.
-
Thank you.
Here is main.qml and styles don't work yet! That is, when I use them this way no button will be shown on output.import QtQuick 2.8 import QtQuick.Window 2.2 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 Window { visible: true width: 700 height: 600 title: qsTr("Transformation") Column { spacing: 10 Transformation { id: transformation } Button { id: t_o_button text: "test_overlap" style: ButtonStyle onClicked: transformation._test_overlap() } Button { id: t_t_button text: "test_transformed" style: ButtonStyle onClicked: transformation._test_transformed() } Button { id: quit_button text: "Quit" style: ButtonStyle onClicked: close() } } }
In programs, for example like this, how should use the components in main.qml? It seems that every component has the instances of another component in itself and we instantiate the most top component, on a hierarchy when each has instances of the the lower one. Right?
-
@tomy About Controls1 styles: http://doc.qt.io/qt-5/qtquick-usecase-styling.html
About using components: http://doc.qt.io/qt-5/qtqml-syntax-basics.html -
About Controls1 styles: http://doc.qt.io/qt-5/qtquick-usecase-styling.html
Thank you, done.
About using components: http://doc.qt.io/qt-5/qtqml-syntax-basics.html
Thanks it was useful. But not exactly spotting what I meant!
I didn't mean parent-child relationship.Look please, the program, when run, starts from somewhere and meets main.qml, ClickableImage.qml and Transformation.qml. The the output will be shown.
I meant, where in the components above firstly the program is started, then where it goes and where again until it finishes and shows the result on output. -
@tomy Maybe I now understand your question. Do you want to know how the objects and the object structure is created? In C++, javascript and many other languages there's a clear order of things which you can follow by reading the code. It starts with main.cpp and you can continue from there, read the code and tell what happens. But QML is declarative in nature. It means that in the code you tell what you want to get but how it's actually done is up to the QML engine. There's no predetermined initialization order which you can rely on. The code means for example:
"I want to get a structure of visual items where there's a top level window which has this and this control elements inside it in these visual places. The color of this one will change according to the state of that one. When this button is pressed such and such should happen." There are several possible ways how this can be achieved and you don't need to know it. The engine could for example read the code and go through the object structure several times and do different initialization steps each time. What you can rely on is that after the UI is rendered and it starts listening to user interactions everything is initialized according to the intentions you expressed in the code.
Logically and in practice initialization must begin somewhere; the starting point is usually main.qml but you give the name in (usually) main.cpp to the engine. The object tree will have the topmost object in main.qml as the root. In your main.qml the engine instantiates Window, inside it a Column, inside that a Transformation and Buttons. When it instantiates Transformation it must of course instantiate Item, Image and MouseArea which are inside that Transformation, and so on. But in which order everything actually is initialized and when everything is ready is up to the engine.
Did that answer your question or did you have something else in mind?
-
Did that answer your question or did you have something else in mind?
It did, yes. I understood the initialisation and it's logical because when no, say, button is clicked why initialising it!
For completing my understanding please also take a look at this:
When I run that program, it firstly goes to main.cpp and loads main.qml from there.
In main.qml we have a window, it will be set and an instance of Transformation which is created by:Transformation { id: transformation }
(the id: transformation is not even mandatory for having an instance of the component Transformation, I suppose)
When we created an instance this way, then the engine/system/even loop (whatever), goes to the definition/declaration of that component (Transformation).
It sees that it has an Item as root, an Image, a MouseArea and a few ClickableImage "instances", so it therefore goes to the ClickableImage component (ClickableImage.qml) and sees an Image and MouseArea there too.
After these the engine/system gets back to the main.qml and puts whatever Transformation component has on the screen followed by the three buttons declared below.
Not very wrong?
-
I understood the initialisation and it's logical because when no, say, button is clicked why initialising it!
By "initialization" I mean the phase before the object tree is fully constructed so that all objects which are reached by the declared tree are ready and all properties have expected values. So a button is initialized even if it's never clicked.Otherwise what you said is a logical way to see it. However, we must keep in mind that this may still be different from the actual execution order of initialization. For example it's undermined in which order a structure like
Item{ //properties... Rectangle{ //properties... Rectangle{} } Button{ //properties... } }
is actually initialized: whether Item's all properties will be ready before the outer Rectangle's or whether the Button is ready before the Rectangles. The idea of the declarative nature of QML is that you don't need to know.
-
Thank you. I think I got all that was needed.