QtQuick: Resize two textfields with Elide on both - qt

I've got two Labels A and B in a row which need to be anchored together such that there is no spacing between them. A is not allowed to be larger than it's content, because B is like a detail label. It would be weird to see Google Chrome_____(the current browser). You'll want Google Chrome (the current browser)____ in this case.
Both have a common parent that they can fill up. Content-wise both A and B can be the larger of the two. The whole thing should be left aligned such that A is anchored to the parent's left and B.left == A.right.
When there is not enough space, both items should shrink and elide until they fit the parent, eg Google Chr..(The current br...
This last part is what I could not figure out how to do.
I'm using 2 labels instead of 1 because they need their own elision and their own styling.
My current solution will simply elide B, not shrink A at all.
RowLayout
{
spacing: 0
anchors.left: parent.left
anchors.right: customisedSettings.left
anchors.leftMargin: UM.Theme.getSize("default_margin").width
Label
{
id: textLabelA
text: qualityName()
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text")
Layout.margins: 0
height: contentHeight
verticalAlignment: Text.AlignVCenter
renderType: Text.NativeRendering
elide: Text.ElideRight
function qualityName() {
[...]
}
}
Label
{
id: textLabelDetail
text: activeQualityDetailText()
font: UM.Theme.getFont("default")
color: UM.Theme.getColor("text_detail")
anchors.verticalCenter: textLabelA.verticalCenter
Layout.margins: 0
Layout.fillWidth: true
height: contentHeight
verticalAlignment: Text.AlignVCenter
renderType: Text.NativeRendering
elide: Text.ElideRight
function activeQualityDetailText()
{
[..]
}
}
}

You can do that by putting them in a RowLayout and setting Layout.fillWidth: true on both of them so they both shrink.
To ensure that the first Label isn't larger than needed, set Layout.maximumWidth: implicitWidth.
This gives us :
import QtQuick 2.8
import QtQuick.Controls 2.1
import QtQuick.Window 2.3
import QtQuick.Layouts 1.2
Window {
visible: true
width: 600
height: 400
RowLayout {
anchors.fill: parent
Label {
text: "Google Chrome"
Layout.fillWidth: true
Layout.maximumWidth: implicitWidth
elide: Text.ElideRight
}
Label {
text: "(the current browser)"
color: "darkgray"
Layout.fillWidth: true
elide: Text.ElideRight
}
}
}

Related

How to increase height of Rectangle according to text in QML

I am not able to increase height of Rectangle (or RowLayout) wrapped around Text item that could dynamically change (chat message for example).
I tried bunch of approaches (Text.paintedHeight, childrenRect ...) but everything looks funky when text is wrapped.
My goal is display chat messages, stretch them according their wrapped text height.
Thanks for any input.
import QtQuick 2.0
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
ApplicationWindow {
visible: true
width: 900
height: 500
ColumnLayout {
width: parent.width
spacing: 2
RowLayout {
id: rowLayout
spacing: 3
Rectangle {
height: 50
width: 50
color: "red"
}
Rectangle {
id: rectangle
width: 50
color: "green"
Layout.fillHeight: true
Layout.fillWidth: true
Text {
id: element
text: "If the GridLayout is resized, all items in the layout will be rearranged. It is similar to the widget-based QGridLayout. All visible children of the GridLayout element will belong to the layout. If you want a layout with just one row or one column, you can use the RowLayout or ColumnLayout. These offer a bit more convenient API, and improve readability.\n\nBy default items will be arranged according to the flow property. The default value of the flow property is GridLayout.LeftToRight.\n\nIf the columns property is specified, it will be treated as a maximum limit of how many columns the layout can have, before the auto-positioning wraps back to the beginning of the next row. The columns property is only used when flow is GridLayout.LeftToRight."
anchors.rightMargin: 10
anchors.leftMargin: 10
anchors.fill: parent
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
wrapMode: Text.WordWrap
clip: false
font.pixelSize: 12
}
}
}
}
}
You have to specify the implicitHeight and implicitWidth for Rectangle (and Item for that matter).
Rectangle {
id: rectangle
width: 50
color: "green"
Layout.fillHeight: true
Layout.fillWidth: true
implicitWidth: element.implicitWidth
implicitHeight: element.implicitHeight
Text {
id: element
anchors.fill: parent
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignLeft
wrapMode: Text.WordWrap
clip: false
font.pixelSize: 12
}
}
Please note that your current setup with anchors.margins is slightly conflicting here, since that is not counted in the implicitHeight/Width, so I left them out.
Another option would be to set the background for a Label (from QtQuick.Controls) to your desired Rectangle, that will then be stretched properly:
Label {
leftPadding: 10
rightPadding: 10
...
background: Rectangle {
color: "green"
}
}
In my opinion this would give you easier control about the position of your text.

TextArea problematic background QML QT

Trying different code combinations and partially solving my problem I came across a behavior that I can not quite explain. So to the point, When I create a simple TextArea without Scrollview it looks like this:
RowLayout {
id: rowLayout
Rectangle{
height: 50
width: 295
TextArea {
id: textArea
text: (" message...")
wrapMode: Text.WrapAnywhere
anchors.fill: parent
}
}
Text area creates a default background. And now I want to do TextArea with ScrollView ALSO with the default TextArea background but it comes out something like that :
RowLayout {
id: rowLayout
Rectangle{
height: 50
width: 295
ScrollView {
id: scrollView1
anchors.fill: parent
TextArea {
id: textArea
text: (" message...")
wrapMode: Text.WrapAnywhere
}
}
}
The only chance to set the default TextArea background is set implicitHeight,implicitWidth but then after entering the text into a TextArea until the scrollbar appears, the background extends over the entire length by going behind the other components like this :
RowLayout {
id: rowLayout
Rectangle{
//color: "#00000000"
height: 50
width: 295
ScrollView {
id: scrollView1
anchors.fill: parent
TextArea {
id: textArea
text: (" message...")
wrapMode: Text.WrapAnywhere
implicitHeight: 50
implicitWidth: 295
}
}
}
So the only thing I want is a scrollable textarea but with this black default background and NOT my background which I can do with rectangle.
Can anyone take a look?
Thank you :)
I tried do my best. Check the example below, hope it will help =)
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
ApplicationWindow {
visible: true
width: 400
height: 400
RowLayout {
width: 295
height: 50
anchors.centerIn: parent
ScrollView {
Layout.fillHeight: true
Layout.fillWidth: true
background: Rectangle { color: "black" }
TextArea {
id: messageField
placeholderText: qsTr("message...")
color: "white"
wrapMode: TextArea.WrapAnywhere
}
}
}
}
Result:

Margin isn't working in qml

I am making UI for a game. When I tried to put margin for the image tab.png
It doesn't reflect any changes to it. It stays where it was before. I also tried to solve this problem by adding the margins through the Layout and by adding it outside the rectangle and row layout but nothing happened.
Also when I am adding margin to the bottom to the user.png to shift it a bit upward, it isn't shifting. So please help me out to solve this. I want to position the tab.png as this layout
The second circle is where I want to place the tab.png. The output of the code
Window {
visible: true
width: 800
height: 600
title: qsTr("Main screen")
ColumnLayout{
spacing: 0
anchors.fill: parent
Item {
id: titlebar
Layout.preferredHeight: 60
Layout.fillWidth: true
RowLayout {
anchors.fill: parent
spacing: 0
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: "black"
Image {
source: "qrc:/img/tab.png"
anchors.leftMargin: undefined
Layout.leftMargin: 20
}
}
Rectangle {
Layout.preferredWidth: 100
Layout.fillHeight: true
color: "#f46b42"
/*Text {
anchors.centerIn: parent
text: "Actions"
}*/
Image{
id:image_user
source: "qrc:/img/user.png"
anchors.verticalCenter: parent.verticalCenter
anchors.verticalCenterOffset:
anchors.left=parent.left
anchors.leftMargin: 10
clip: true
}
Item{
id:text_content
anchors.centerIn: parent
anchors.bottomMargin: 20
Text{
id:text_user
text: "User"
anchors.bottom:text_value.top
anchors.bottomMargin: 4
}
Text{
id:text_value
text:"$ 2000"
color:"yellow"
}}
}
}
}
Rectangle {
id: content
Layout.fillHeight: true
Layout.fillWidth: true
color: "lightyellow"
Text {
anchors.centerIn: parent
}
Column{
spacing: 1;
Repeater{
id:mmm
model: 5
Rectangle{
id:imgl
width: 100
height: 100
color: "#4286f4"
property string src: ""
MouseArea{
anchors.fill:parent
onClicked: {
parent.color="";
}
}
Image {
id: imgx
source: parent.src;
anchors.verticalCenter: parent.verticalCenter
}
onParentChanged: {
mmm.itemAt(0).src="qrc:/img/5by90.png";
mmm.itemAt(1).src="qrc:/img/6by42.png";
mmm.itemAt(2).src="qrc:/img/12by24.png";
mmm.itemAt(3).src="qrc:/img/fortune.png";
mmm.itemAt(4).src="qrc:/img/mini-roulette.png";
}
}
}
}
}
}
}
Layouts only affect your direct children, not the children of the children., so Layout.leftMargin: 20 will not affect Image as you see in this case.
The solution is really simple, it establishes the property x: 20 since the position of item is with respect to the parent's topleft position
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: "black"
Image {
x:20
source: "qrc:/img/tab.png"
}
}
Inside Rectangle, for child elements, you need to use anchors.margin, whereas for Layouts child element can use Layout.margin.You need to use anchors.leftMargin: as Parent is Rectangle, Layout.margin will not have any effect.
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: "black"
Image {
source: "qrc:/img/tab.png"
anchors.leftMargin: 20
}
}

How to design a multi-level fluid layout in QML

I have designed a layout in QML to learn more about its features and have some questions on the "Best Practices" in designing such layout. Here it is:
It is essentially a ColumnLayout consisted of three RowLayouts, each one with some Rectangles. The size of each Row and Rectangle should be calculate such as:
First row: Height = 40%, Width = 100%
Red Rectangle filling the whole area
Second row: Height = 20%, Width = 100%
Dark-green Rectangle: Height = 100%, Width = 20%,
Light-green Rectangle: Height = 100%, Width = 80%
Third row: Height = 40%, Width = 100%
Dark-blue Rectangle: Height = 100%, Width = 40%,
Blue Rectangle: Height = 100%, Width = 20%
Light-blue Rectangle: Height = 100%, Width = 40%
The QML I have came up with is working and is in the following. I have some questions about it:
I have set the width and height percentages using Layout.preferredHeight: x*parent.height pattern. Other options caused some issues (e.g. preferredHeight caused binding loop warnings). Is my approach correct and efficient?
As a hack, I set Layout.fillWidth: true for the first element of Row #2 and Row #3, which doesn't make sense to me, but does work. If I set their width as percentage (e.g. Layout.preferredWidth: 0.2*parent.width) their row will collapse to width 0. Is this an expected behavior? Is there any better workaround?
Do you have any recommendation on the layouts? Am I on the right path?
Here is my QML code for the layout:
ApplicationWindow {
x: 500
y: 100
width: 250
height: 150
visible: true
ColumnLayout {
anchors.fill: parent
spacing: 0
RowLayout {
spacing: 0
Layout.preferredHeight: 0.4*parent.height
Layout.fillHeight: false
Rectangle {
Layout.fillHeight: true
Layout.fillWidth: true
color: "red"
}
}
RowLayout {
spacing: 0
Layout.preferredHeight: 0.2*parent.height
Layout.fillHeight: false
Rectangle {
Layout.fillHeight: true
Layout.fillWidth: true
color: "darkGreen"
}
Rectangle {
Layout.fillHeight: true
Layout.preferredWidth: 0.8*parent.width
color: "lightGreen"
}
}
RowLayout {
spacing: 0
Layout.preferredHeight: 0.4*parent.height
Layout.fillHeight: false
Rectangle {
Layout.fillHeight: true
Layout.fillWidth: true
color: "darkBlue"
}
Rectangle {
Layout.fillHeight: true
Layout.preferredWidth: 0.2*parent.width
color: "blue"
}
Rectangle {
Layout.fillHeight: true
Layout.preferredWidth: 0.4*parent.width
color: "lightBlue"
}
}
}
}
Update:
My approach seems to be more hacky than I expected:
Putting Text elements as children in this layout raises binding loop warnings like:
QML QQuickLayoutAttached: Binding loop detected for property "preferredWidth"
If a wrap Text inside a Rectangle the warnings disappear.
The spacing: 0 seems to play an important role. Omitting it will causes binding loop warnings.
While my approach to fluid layout design in QML works, it has some serious issue and might not fall under the "best practices".
While both other answers show valid solutions, I believe both the question being asked and the two solutions somehow miss the point of using Layouts.
Basically, Layouts are made to bring together Items that have an implicit size (implicitHeight/implicitWidth). Layout.preferredWidth/Layout.preferredHeight are used to override these things in some rare situations, see below. The "Qt Quick Layouts - Basic Example" coming with Qt does not use Layout.preferredWidth/Layout.preferredHeight at all (!) and makes a really nice look, without contaminating the whole qml file with either anchors or Layout properties. It takes some learning to be able to do this oneself, but once you got used to it, Layouts are a way to define user interfaces more directly with less code.
What confused me the most at the beginning were the following things:
RowLayout/ColumnLayout/GridLayout come with Layout.fillWidth/Layout.fillHeight set to true, so when putting these near an Item/Rectangle then the Items/Rectangles suddenly disappear, because they don't have set these values (i.e. they have Layout.fillWidth/Layout.fillHeight set to false).
Items/Rectangles come with an implicitHeight/implicitWidth of 0, meaning they don't really play nice side-by-side with Layouts. The best thing to do is to derive implicitWidth/implicitHeight from contained subitems, like a RowLayout/ColumnLayout itself does by default for its subitems.
Layout.preferredWidth/Layout.preferredHeight can be used to overcome implicit sizes where they are already defined and cannot be set. One such place is directly in a layout item, another is e.g. a Text item which also doesn't let you override implicit sizes.
Considering these points, I would write the example in the following way. I removed unnecessary items to better illustrate when Layout.fillwidth/Layout.fillheight are needed, and when it is better to use implicitWidth in my opinion.
import QtQuick 2.9
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.3
ApplicationWindow {
width: 250
height: 150
visible: true
ColumnLayout {
spacing: 0
anchors.fill: parent
Rectangle {
implicitHeight: 40
Layout.fillHeight: true
Layout.fillWidth: true
color: "red"
}
RowLayout {
spacing: 0
Layout.preferredHeight: 20
Rectangle {
implicitWidth: 20
Layout.fillHeight: true
Layout.fillWidth: true
color: "darkGreen"
}
Rectangle {
implicitWidth: 80
Layout.fillHeight: true
Layout.fillWidth: true
color: "lightGreen"
}
}
RowLayout {
spacing: 0
Layout.preferredHeight: 40
Rectangle {
implicitWidth: 40
Layout.fillHeight: true
Layout.fillWidth: true
color: "darkBlue"
}
Rectangle {
implicitWidth: 20
Layout.fillHeight: true
Layout.fillWidth: true
color: "blue"
}
Rectangle {
implicitWidth: 40
Layout.fillHeight: true
Layout.fillWidth: true
color: "lightBlue"
}
}
}
}
It is forbidden (and unnecessary) to try and reference width and height of the parent from Items inside the Layout.
When fillWidth (or fillHeight) is set to true, then Items are allocated space in proportion to their specified preferredWidth (or preferredHeight).
Therefore the correct way to create your Layout is as follows. I have modified the appearance only to show that spacing and Text can also be set freely as desired. No binding loops.
ApplicationWindow {
x: 500
y: 100
width: 250
height: 150
visible: true
ColumnLayout {
anchors.fill: parent
spacing: 5
RowLayout {
spacing: 5
Layout.preferredHeight: 40
Layout.fillHeight: true
Rectangle {
Layout.fillHeight: true
Layout.fillWidth: true
color: "red"
}
}
RowLayout {
spacing: 5
Layout.preferredHeight: 20
Layout.fillHeight: true
Rectangle {
Layout.fillHeight: true
Layout.preferredWidth: 20
Layout.fillWidth: true
color: "darkGreen"
}
Rectangle {
Layout.fillHeight: true
Layout.preferredWidth: 80
Layout.fillWidth: true
color: "lightGreen"
}
}
RowLayout {
spacing: 5
Layout.preferredHeight: 40
Layout.fillHeight: true
Text {
Layout.fillHeight: true
Layout.preferredWidth: 40
Layout.fillWidth: true
color: "darkBlue"
text: "hello world!"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
Rectangle {
Layout.fillHeight: true
Layout.preferredWidth: 20
Layout.fillWidth: true
color: "blue"
}
Rectangle {
Layout.fillHeight: true
Layout.preferredWidth: 40
Layout.fillWidth: true
color: "lightBlue"
}
}
}
}
QtQuick.Layout does not provide any real improvements over the classical anchoring system. I would recommand to avoid them. You can have way more control over your layout using anchors.
Here is the exact same design without QtQuick.Layout :
ApplicationWindow {
x: 500
y: 100
width: 250
height: 150
visible: true
Column {
anchors.fill: parent
Row {
anchors.left: parent.left
anchors.right: parent.right
height: 0.4 * parent.height
Rectangle {
anchors.top: parent.top
anchors.bottom: parent.bottom
width: parent.width
color: "red"
}
}
Row {
anchors.left: parent.left
anchors.right: parent.right
height: 0.2 * parent.height
Rectangle {
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 0.2 * parent.width
color: "darkGreen"
}
Rectangle {
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 0.8 * parent.width
color: "lightGreen"
}
}
Row {
anchors.left: parent.left
anchors.right: parent.right
height: 0.4 * parent.height
Rectangle {
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 0.4 * parent.width
color: "darkBlue"
}
Rectangle {
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 0.2 * parent.width
color: "blue"
}
Rectangle {
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 0.4 * parent.width
color: "lightBlue"
}
}
}
}
So far I never met any design that was impossible to do without QtQuick.Layout.

Change Font Size of Button in Qt QML

How can the font size of the text in a Button control be set in QML? The designer has not option, and 'font' is not a valid property of Button.
Button {
id: cmdQuit
text: qsTr("Quit")
width: 64
height: 32
}
You set the Button's style property:
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
Rectangle {
id: container
width: 800
height: 800
Button {
id: cmdQuit
text: qsTr("Quit")
width: 64
height: 32
style: ButtonStyle {
label: Text {
renderType: Text.NativeRendering
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
font.family: "Helvetica"
font.pointSize: 20
color: "blue"
text: control.text
}
}
}
}
For QtQuick 2, you have to use the contentItem property as shown here: https://doc.qt.io/qt-5/qtquickcontrols2-customize.html#customizing-button
import QtQuick 2.12
import QtQuick.Controls 2.12
Button {
id: control
text: qsTr("Button")
contentItem: Text {
text: control.text
font.pointSize: 20
opacity: enabled ? 1.0 : 0.3
color: control.down ? "#17a81a" : "#21be2b"
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
}
This is an old question, but since it comes first in search engines I'm providing an update on the situation.
For QtQuick2, unlike what Chris said, you don't need to use the contentItem property anymore. You can access the font property directly from Button.
Example:
Button {
id: btn
text: "Test"
font.pixelSize: 18
}

Resources