QML ignores width and height when setting anchors - layout

I'm trying to understand how anchors work in QML (Qt Quick 2.0). I've got a simple Item like this:
AddButton.qml:
Item {
Button {
text: "ADD"
width: 100
height: 50
}
}
Which I add to the main QML file like this:
main.qml:
Item {
id: root
width: 800
height: 600
AddButton {
id: addButton
}
}
This works fine. However, as soon as I try to put the button in the bottom right corner using anchors, the button disappears:
main.qml:
Item {
.....
AddButton {
id: addButton
anchors.right: parent.right
anchors.bottom: parent.bottom
}
}
It only comes back if I set a width and height at the main QML file level:
main.qml:
Item {
.....
AddButton {
id: addButton
width: 100
height: 50
anchors.right: parent.right
anchors.bottom: parent.bottom
}
}
So I'm wondering, why does the button disappear when I set the anchors? And is there any way to make it work without setting the width and height in the main QML file (basically to make it use whatever size is set in AddButton.qml?)

The problem is that the encapsulating Item has not an explicit width height. In this case the engine refers to the "natural" witdh/height, i.e. the implicitWidth/implicitHeight properties. Such properties happen to be zero in most cases, even in this specific case. Hence, your custom type has zero dimension.
Therefore the AddButton.anchors.bottom is in fact at the very top of the encapsulated Button, which in turn protrudes the encapsulating Item
There are two things about this:
You don't need to encapsulate the Button with an Item unless you want to hide the internals of the Button.
If the latter is your desire, try this:
Item {
width: 100 //give the object a dimension!
height: 50
Button {
text: "ADD"
anchors.fill: parent
}
}
Now you can anchor it, and it won't be positionated somewhere else.

Related

How to close a drawer popup with a specific button/area outside it in QML?

I've created a drawer and I wish to close it by pressing the same button that triggers it. This button is outside the drawer. But QML doesn't seem to allow this as the only closepolicy (drawer property to close) options for Popups are:
Popup.NoAutoClose (where I have to click and drag the drawer to close it)
Popup.CloseOnPressOutside (anywhere outside)
Popup.CloseOnPressOutsideParent (anywhere outside) (default)
Popup.CloseOnReleaseOutside Popup.CloseOnReleaseOutsideParent
Popup.CloseOnEscape (only on escape button) (default)
Also, I don't seem to be able to click any button outside the drawer when it is visible/drawn for some reason. If that wasn't the case, I wouldn't have this issue either.
Can I make the drawer close by clicking on a specific button/area outside it?
Does anyone know the solution to this?
Thanks in advance!
Drawer inherited from Popup so we can take those advantages to control the behavior. By setting the model: false and closePolicy: Popup.NoAutoClose it is possible to control the drawer from button actions.
Window {
id: window
width: 640
height: 480
visible: true
Drawer {
id: drawer
width: 0.4 * window.width
height: window.height
closePolicy: Popup.NoAutoClose
modal: false
}
Button {
text: drawer.visible ? "close" : "open"
anchors.centerIn: parent
onClicked: {
drawer.visible = !drawer.visible
}
}
}

Arabic font in Phaser.js

Hi I wanted to add some Arabic text to my Phaser game. I have the following in the update() function:
this.scoreText = this.add.text( this.world.centerX, this.world.height/5,
"",{nsize: "32px", fill: "#FFF", align: "center"});
this.scoreText.setText("تُفاحة");
This produces strange letters on the screen which are not Arabic. Any ideas?
First off, you shouldn't be adding text in the update() method - this would cause it to be added multiple times (once for each frame, ideally 60 times per second). Move it to the create() method so that it's only added once. You also have a typo in the parameters: nsize should be just size.
function create() {
this.scoreText = this.add.text( this.world.centerX, this.world.height / 5, "", { size: "32px", fill: "#FFF", align: "center" });
this.scoreText.setText("تُفاحة");
}
You can try something like
Import the font in the CSS part in index.html
#import url(https://fonts.googleapis.com/earlyaccess/amiri.css);
Then just declare the style as a variable
var style = { font: "32px Amiri", fill: "#333", align: "center" };
Then in the create function add the text like in this jsfiddle https://jsfiddle.net/albator2018/r2zLtoqd/
There is another manner to do it but like what i've just explained it works fine

How to wrap some text in a rectangle in QML?

I have to perform a very simple task: I want to display a piece of text inside a rectangle and the size of that rectangle should precisely be the width of the text.
In C++, it's fairly easy to do. Just define the QString and apply the QFontMetrics to get its width. Then define the rectangle graphics element to have that size. It's done within five minutes.
I have heard that QML is easier to use. Therefore, I was expecting to solve that problem in less than five minutes. I didn't, and I'm still stuck at it. Here's what I have tried:
Rectangle {
width: myText.contentWidth
height: myText.contentHeight
Text {
anchors.fill:parent
id: myText
font.family: "Helvetica"
font.pointSize: 50
text: qsTr("The string I want to display")
}
}
This doesn't work for some reason I don't understand. I have found a way to do it in a way that doesn't exactly suits my needs:
Rectangle {
width: 100
height: 100
MouseArea {
id: myMouseArea
anchors.fill: parent
onClicked: parent.width=myText.contentWidth
hoverEnabled: true
}
Text {
anchors.fill:parent
id: myText
font.family: "Helvetica"
font.pointSize: 50
text: qsTr("The string I want to display")
}
}
In this case, when I click the rectangle, it gets the correct width. Nevertheless, I am not interested in this solution, because I don't want to have to click to get a rectangle with the correct size.
I want that the rectangle's size gets the correct size whenever myText changes text. The use of onTextChanged in the Text item doesn't work either.
What am I missing here?
As far as I know, Font metrics were made available to developers in Qt 5.4, so they are relatively new, in QML. You got mainly FontMetrics and TextMetrics. A simple usage example:
import QtQuick 2.4
import QtQuick.Window 2.2
Window {
visible: true
width: 280; height: 150
TextMetrics {
id: textMetrics
font.family: "Arial"
font.pixelSize: 50
text: "Hello World"
}
Rectangle {
width: textMetrics.width
height: textMetrics.height
color: "steelblue"
Text {
text: textMetrics.text
font: textMetrics.font
}
}
}
As noted by Phrogz in the comment below, the TextMetrics type does not support measuring wrapped text.
EDIT
For what is worth I've never ever had the need to use metrics in QML. For me content* or painted* properties served the purpose and, as of Qt 5.12, they seem to work fine. Aka the following two solutions generate the correct visual behaviour:
// solution 1
Rectangle {
width: myText.contentWidth
height: myText.contentHeight
Text {
anchors.fill:parent
id: myText
font.family: "Helvetica"
font.pointSize: 50
text: qsTr("The string I want to display")
}
}
// solution 2
Rectangle {
width: myText.paintedWidth
height: myText.paintedHeight
Text {
anchors.fill:parent
id: myText
font.family: "Helvetica"
font.pointSize: 50
text: qsTr("The string I want to display")
}
}
I would prefer those solutions to the usage of metrics for such a simple use case as the one proposed by the OP. For the opposite case - fitting a text in a specific size - a combination of properties can do the trick, e.g.:
Rectangle {
anchors.centerIn: parent
width: 200
height: 30
Text {
anchors.fill: parent
text: "Wonderful Text"
minimumPixelSize: 2
fontSizeMode: Text.Fit
font.pixelSize: 200
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
Here the pixel size is simply over the top but the text still fits because a minimum size of 2 is set and the text has a clear fitting policy and clear boundaries, defined by the anchoring.
I'm sure Label component will do the job:
import QtQuick 2.1
import QtQuick.Controls 2.4
ApplicationWindow {
visible: true
Column {
Repeater {
model: [
{"color": "red", "radius": 1},
{"color": "green", "radius": 2},
{"color": "blue", "radius": 3}
]
Label {
padding: 0
text: modelData.color
font.family: "Helvetica"
font.pointSize: 50
background: Rectangle {
color: modelData.color
radius: modelData.radius
}
}
}
}
}
You don't need to use anchors.fill: parent for Text item because size of Text's parent depends on size of Text itself. It's cause binding loop.
This must works fine.
Rectangle {
width: myText.contentWidth
height: myText.contentHeight
Text {
id: myText
font.family: "Helvetica"
font.pointSize: 50
text: qsTr("The string I want to display")
}
}

QML scope: property binding in child object failing

I'm new to QML and ran into a scope problem while going a button tutorial. I solved it but I don't understand why the code didn't work in the first place:
Problem
The following code gives Runtime reference errors when the button is hovered over:
main_broken.qml
import QtQuick 2.0
import QtQuick.Controls 1.1
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Button Tester")
Rectangle {
id: simpleButton
height: 75
width: 150
property color buttonColor: "light blue"
property color onHoverColor: "gold"
property color borderColor: "white"
onButtonClick: {
console.log(buttonLabel.text + " clicked")
}
signal buttonClick()
Text {
id: buttonLabel
anchors.centerIn: parent
text: "button label"
}
MouseArea {
id: buttonMouseArea
anchors.fill: parent
onClicked: buttonClick()
hoverEnabled: true
onEntered: parent.border.color = onHoverColor
onExited: parent.border.color = borderColor
}
color: buttonMouseArea.pressed ? Qt.darker(buttonColor, 1.5) : buttonColor
scale: buttonMouseArea.pressed ? 0.99 : 1
}
}
errors:
qrc:///main.qml:37: ReferenceError: onHoverColor is not defined
qrc:///main.qml:38: ReferenceError: borderColor is not defined
qrc:///main.qml:37: ReferenceError: onHoverColor is not defined
qrc:///main.qml:35: ReferenceError: buttonClick is not defined
Solution
Solved by just moving the property bindings and signal-slot into the Application window object as follows:
main_fixed.qml
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Button Tester")
property color buttonColor: "light blue"
property color onHoverColor: "gold"
property color borderColor: "white"
onButtonClick: {
console.log(buttonLabel.text + " clicked")
}
signal buttonClick()
//etc
Questions
Why is it not possible to leave the property bindings within the Rectangle child of the ApplicationWindow object?
What if you wanted to have properties exclusive only to the rectangle (e.g. colour), but that used some of the properties of the ApplicationWindow (e.g. text size)?
I am new to coding and stack overflow (this is my first post). I've tried to ask my question in the clearest way possible, but please let me know if it's not up to par with stack overflow's standards and what I must do to change it.
Scope in QML is easy, maybe weird, but easy :
When you use an identifier, lets say foo in a var binding, QML engine search in this order :
an object in the current file that has foo as its ID
an object in global scope (main QML file) that has foo as its ID
a property in current object that is called foo
a property in the root object of current component (current file) that is called foo
If it does not find it, it throws ReferenceError.
And no, immediate parent or child is not in the scope. That can seem weird, but that's the way it works.
If you need an out-of-scope variable to be referenced, just use an ID before it : if the object is called foo and has a property named bar, you can reference foo.bar wherever you wan't in the file.
Hope it helps.

JavaFX TextArea Hiding Scroll Bars

I have a TextArea() and would like to hide the vertical/horizontal scroll bars. I see that the control seems to have a built in scroll-pane that shows as needed.
TextArea numberPane = new TextArea();
numberPane.setEditable(false);
numberPane.setMaxWidth( 75 );
// Set the characteristics of our line number pane
numberPane.setId( "line-number-pane" );
In my CSS file I have the follow settings.
#line-number-pane
{
-fx-text-fill: white;
-fx-background-color: black;
-fx-font: 12px "Courier New";
-fx-font-family: "Courier New";
-fx-font-weight: bold;
}
#line-number-pane .scroll-pane
{
-fx-hbar-policy : never;
-fx-vbar-policy : never;
}
As expected the text area font/color/size works just fine. However, the scroll-pane policy doesn't seem to work.
Should I be able to hide the scroll bars via the CSS file or is there some code that will do the trick.
Thanks.
From How can I hide the scroll bar in TextArea?:
Remove Horizontal Scrollbar
textArea.setWrapText(true);
Remove Vertical Scrollbar
ScrollBar scrollBarv = (ScrollBar)ta.lookup(".scroll-bar:vertical");
scrollBarv.setDisable(true);
CSS
.text-area .scroll-bar:vertical:disabled {
-fx-opacity: 0;
}
I just did it very simply using a StyleSheet:
CSS
.text-area .scroll-bar:vertical {
-fx-pref-width: 1;
-fx-opacity: 0;
}
.text-area .scroll-bar:horizontal {
-fx-pref-height: 1;
-fx-opacity: 0;
}
No need for all that whacky code.
I observed code of TextAreaSkin class, and found, that a
void layoutChildren(x, y, w, h) method, which is called "during the layout pass of the scenegraph" and de facto, each time, when something happens with a control, contains a code, which changes hbarPolicy and vbarPolicy between AS_NEEDED and NEVER, according to the current state of control.
So, looks like, there is no chance to do somethign with it, using a css.
Try to just make scrollbars invisible. But, as I see code of ScrollPaneSkin, scrollBars are created once, but their visibility state seems to change during the control is working, so, instead of using setVisible(false) (which will be ignored in the nearest layout), try to use a setOpacity(0.0). (I'm not sure, it will work, but it worth to try).
Also, instead of CSS using, you can apply a recursive search of scrollBars in a control structure, using a Parent.getChildrenUnmodifiable() method, and make them invisible manually.

Resources