Error when customizing Controls 2 SpinBox - qml

When customizing a QtQuickControls2 SpinBox, I get this error in the console when closing my application :
"There are still \"2\" items in the process of being created at engine destruction."
The number varies depending on how many Spinboxes are in the windows, it goes up for every indicator that was customized (two times per customized SpinBox : one for the up indicator, one for the down indicator). I tried commenting out each part of my custom code, as well as using the example code provided here, so I am positive that this is where the error comes from.
Does anyone know how to get rid of this error ?
Main window code :
import QtQuick 2.7
import QtQuick.Controls 2.3
ApplicationWindow{
width: 1600
height: 900
visible: true
SpinBox_custom{
}
}
Custom SpinBox_custom code :
import QtQuick 2.11
import QtQuick.Controls 2.4
SpinBox {
id: control
value: 50
editable: true
contentItem: TextInput {
anchors.fill: parent
anchors.rightMargin : up.indicator.width
anchors.leftMargin : down.indicator.width
z: 2
text: control.textFromValue(control.value, control.locale)
font.pointSize: Style.textPointSize-2
color: '#7e8d9e'
selectionColor: '#7e8d9e'
selectedTextColor: "white"
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
readOnly: !control.editable
validator: control.validator
inputMethodHints: Qt.ImhFormattedNumbersOnly
}
up.indicator: Rectangle {
x: control.mirrored ? 0 : parent.width - width
height: parent.height
implicitWidth: 20
implicitHeight: 30
color: control.up.pressed ? '#dee2e6' : '#bec6ce'
border.color: enabled ? '#bec6ce' : '#dee2e6'
Text {
text: "+"
font.pixelSize: control.font.pixelSize * 2
color: '#428AC9'
anchors.fill: parent
fontSizeMode: Text.Fit
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
down.indicator: Rectangle {
x: control.mirrored ? parent.width - width : 0
height: parent.height
implicitWidth: 20
implicitHeight: 30
color: control.down.pressed ? '#dee2e6' : '#bec6ce'
border.color: enabled ? '#bec6ce' : '#dee2e6'
Text {
text: "-"
font.pixelSize: control.font.pixelSize * 2
color: '#428AC9'
anchors.fill: parent
fontSizeMode: Text.Fit
horizontalAlignment: Text.AlignHCenter
verticalAlignment: Text.AlignVCenter
}
}
background: Rectangle {
implicitWidth: 90
}
}

I've just faced the same problem and after some experiments seemed to find that it's somewhat connected to assigning literal values to the value property of SpinBox.
Something similar is also discussed in this report, and these are other things asking for trouble when used in SpinBox mentioned there:
references between internal elements of SpinBox (contentItem, background, [up,down].indicator's)
references to parent in internal elements
assigning id to internal elements
After getting rid of all of that and also changing value: 0 to value: from it automagically stopped warning me with the message in the original post.
Just as a reference, here's the snippet which works for me without the warning:
SpinBox
{
id: control
value: from
from: 0
to: 600
editable: true
enabled: true
leftPadding: topPadding
rightPadding: height
contentItem: Item
{
anchors.left: control.left
anchors.top: control.top
anchors.bottom: control.bottom
implicitWidth: input.implicitWidth
implicitHeight: input.implicitHeight
width: control.width - control.height
height: control.height
TextInput
{
id: input
anchors.fill: parent
text: control.textFromValue(control.value, control.locale)
color: "black"
horizontalAlignment: Qt.AlignHCenter
verticalAlignment: Qt.AlignVCenter
readOnly: !control.editable
validator: control.validator
inputMethodHints: Qt.ImhFormattedNumbersOnly
}
}
up.indicator: Rectangle
{
anchors.top: control.top
anchors.right: control.right
anchors.topMargin: 1
anchors.rightMargin: 1
height: control.height / 2
width: control.height
color: "gold"
}
down.indicator: Rectangle
{
anchors.bottom: control.bottom
anchors.right: control.right
anchors.bottomMargin: 1
anchors.rightMargin: 1
height: control.height / 2
width: control.height
color: "orange"
}
background: Rectangle
{
implicitWidth: 100
border.color: "red"
border.width: 1
radius: 2
}
}

Related

QML Change ScrollBar Handle Color

I want to change the scrollbar handle color, and follow the Qt doc
https://doc.qt.io/qt-5/qtquickcontrols2-customize.html#customizing-scrollbar
here is my code.
ScrollView {
id: view
anchors.top: parent.top
anchors.left: parent.left
contentHeight: 300
contentWidth: view.width
width: 200
height: 200
focus: true
ScrollBar.horizontal.policy: ScrollBar.AlwaysOff
Label {
text: "ABC"
font.pixelSize: 224
}
background: Rectangle{
color:"pink"
}
ScrollBar.vertical: ScrollBar {
parent: view
id: control
active: true
contentItem: Rectangle {
implicitWidth: 6
implicitHeight: 100
radius: width / 2
color: control.pressed ? "#81e889" : "#c2f4c6"
}
}
}
enter image description here
this result the handle will fill with scrollbar.
how to changed handle color and do not fill scrollbar?
here is update.
Try to setting implicitHeight to view.contentHeight
ScrollBar.vertical: ScrollBar {
parent: view
id: control
active: true
contentItem: Rectangle {
implicitWidth: 6
implicitHeight: view.contentHeight
radius: width / 2
color: control.pressed ? "#81e889" : "#c2f4c6"
}
}
here is result
It is have same problem,it's change the whole ScrollBar, not handle.

QML: Center variable text and image

I need to horizonally center a variable-length text (red box) and an image (yellow box) in a big box (green box). The text shall wrap if it does not fit the box.
Existing code:
Item {
id: bigBox
x: 255
y: 0
width: 800
height: 100
Image {
id: imageBox
source: "image.png"
width: 52
height: 46
anchors.left: parent.left
anchors.leftMargin: 12
anchors.verticalCenter: parent.verticalCenter
horizontalAlignment: Image.AlignLeft
verticalAlignment: Image.AlignVCenter
fillMode: Image.Pad
}
Text {
id: textBox
anchors.left: symbol.right
anchors.leftMargin: 12
anchors.right: parent.right
anchors.verticalCenter: parent.verticalCenter
text: qsTr("heading text")
font.pixelSize: 36
font.bold: true
horizontalAlignment: Text.AlignCenter
}
}
Update:
Actual running code and a real screenshot showing the problem:
import QtQuick 2.0
Rectangle {
id: mask
x: 0
y: 0
width: 800
height: 430
color: "#FFFFFF"
property int pageState: 0
Rectangle {
x: 0
y: 0
width: 111
height: 100
color: "#0000FF"
}
Item {
id: whitespace
x: 117
y: 0
width: 800-x
height: 100
Row {
anchors.centerIn: parent
Image {
id: symbol
source: "../img/pepper.png"
width: 52
height: 46
anchors.verticalCenter: parent.verticalCenter
fillMode: Image.Pad
}
Text {
id: heading
property var texts: ["Active Blabla","Active Blaaaaaaah Blaaaah ","Active Blabla and Blaaaaaaah Blaaaah"]
anchors.verticalCenter: parent.verticalCenter
color: "#333191"
text: texts[pageState]
font.family: "Liberation Sans"
font.pixelSize: 36
font.bold: true
horizontalAlignment: Text.AlignLeft
verticalAlignment: Text.AlignVCenter
wrapMode: Text.WrapAtWordBoundaryOrAnywhere
textFormat: Text.PlainText
width: Math.min(150,contentWidth)
}
}
}
Rectangle {
id: stage
x: 0
y: 106
width: parent.width
height: parent.height-y
color: "#FFFF00"
}
Timer {
interval: 1000 // milliseconds
triggeredOnStart: true
repeat: true
running: true
onTriggered: {
pageState=(pageState+1)%3;
}
}
}
The white area top right is the green box in the first picture. The timer simply runs through the three texts, like the real application would do.
Changing the first parameter of Math.min() to 600 does not change anything.
My set of hacks to solve that problem:
Item {
// ...
Text {
function escapeHTML(text)
{
return text.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");
}
function toHTML(imageUrl,text)
{
var textlines=escapeHTML(text).replace(/\r?\n/,"\n").split("\n");
var retval="<center>";
retval=retval+'<table><tr>';
if (imageUrl!="") {
retval=retval+'<td rowspan="'+(textlines.length)+'"><img src="'+imageUrl+'"></td>';
retval=retval+'<td rowspan="'+(textlines.length)+'"> </td>';
}
for (var i=0; i<textlines.length; i++) {
if (i>0) {
retval=retval+"<tr>";
}
retval=retval+'<td>'+textlines[i]+'</td></tr>';
}
retval=retval+'</table>';
retval=retval+"</center>";
return retval;
}
anchors.fill: parent
verticalAlignment: Text.AlignVCenter
textFormat: Text.RichText
text: toHtml("../img/pepper.png",qsTr("heading"))
}
}
<center> centers the text in the available space, but not the image
(it stays left - bug!).
<table> can be centered by <center>, and it can contain the
image.
Wrapping does not work as expected, so the translated text returned
by qsTr() has to contain linebreaks at the right positions.
toHTML() splits at the linebreaks and generates table rows from that.
The image needs a table cell with rowspan, or else the image is placed too high relative to the text.
And finally, verticalAlignment: Text.AlignVCenter places all of that vertically centered -- except for the table borders that I luckily don't need. (If you are bored, add border=1 to the <table> tag.)
And no, the HTML and CSS subset supported by Text.RichText does not support vertical alignment. The rendering engine behaves like ancient browsers, you have to stack hacks and workarounds as if it was still 1996.
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Layouts 1.2
Item {
id: bigBox
width: 800
height: 100
Row {
anchors.centerIn: parent
Image {
anchors.verticalCenter: parent.verticalCenter
source: "blue.png"
}
Text {
anchors.verticalCenter: parent.verticalCenter
// maximum width of the text
width: Math.min(150, contentWidth)
text: qsTr("heading")
wrapMode: Text.WordWrap
horizontalAlignment: Text.AlignHCenter
}
}
}

Image size different after second click on it

I have following minimal working example, taken from my current project:
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Layouts 1.1
import QtQuick.Controls 1.4
Window {
visible: true
width: Screen.width/2
height: Screen.height/2
property real ueMinOpacity: 0.00
property real ueMaxOpacity: 1.00
Rectangle {
anchors.fill: parent
anchors.margins: 8
border.color: "#4682b4"
radius: 16
clip: true
gradient: Gradient {
GradientStop {
position: 0
color: "#ffffff"
} // GradientStop
GradientStop {
position: 1
color: "#303030"
} // GradientStop
} // Gradient
Rectangle {
anchors.fill: parent
antialiasing: true
border.color: "#4682b4"
border.width: 1
radius: 16
clip: true
gradient: Gradient {
GradientStop {
position: 0
color: "#ffffff"
} // GradientStop
GradientStop {
position: 1
color: "#000000"
} // GradientStop
} // Gradient
RowLayout {
spacing: 8
anchors.fill: parent
TextField {
id: ueProductSearchTextField
antialiasing: true
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignLeft|Qt.AlignVCenter
Layout.margins: 8
placeholderText: qsTr("Enter product info")
} // TextField
Rectangle {
id: ueImageWrapper
Layout.fillWidth: true
Layout.fillHeight: true
Layout.alignment: Qt.AlignRight|Qt.AlignVCenter
Layout.margins: 8
antialiasing: true
border.color: "#4682b4"
border.width: 1
radius: 16
clip: true
visible: ueProductSearchTextField.length > 0
gradient: Gradient {
GradientStop {
position: 0
color: "#636363"
} // GradientStop
GradientStop {
position: 1
color: "#303030"
} // GradientStop
} // Gradient
Image {
anchors.fill: parent
source: "http://www.clipartbest.com/cliparts/9iR/gEX/9iRgEXXxT.png"
antialiasing: true
clip: true
smooth: true
fillMode: Image.PreserveAspectFit
horizontalAlignment: Image.AlignHCenter
verticalAlignment: Image.AlignVCenter
sourceSize.width: 96
sourceSize.height: 96
} // Image
MouseArea {
anchors.fill: parent
enabled: ueImageWrapper.visible
onClicked: {
ueProductSearchTextField.text="";
} // onClicked
} // MouseArea
onWidthChanged: {
print("ueImageWrapper.width:"+ueImageWrapper.width);
} // onWidthChanged
onHeightChanged: {
print("ueImageWrapper.height:"+ueImageWrapper.height);
} // onHeightChanged
} // Rectangle
} // RowLayout
} // Rectangle
} // Rectangle
} // Window
Now, the purpose of this Item/Rectangle is to filter database records according to TextField's entered value, which works perfectly. However, once TextField's text is not empty anymore (when user enters some string), on the right side of Layout Image for clearing text is shown via OpacityAnimator. Once the app is launched, I get following screenshot - clear text icon is hidden since there is not text in TextField:
Then, I enter some text into TextField and clear text icon pops up:
Then, for instance, I clear text by clicking on clear text icon and it (icon) is hidden again, which is ok:
And finally, I reenter text into TextField, clear text icon is visible again, but it has different size:
Why? I did not change the code. It must be some problem with Layouts, but I simply do not see it! Here is also a debug output from onWidthChanged and onHeightChanged handlers:
qml: ueImageWrapper.width:37.56521739130435
qml: ueImageWrapper.height:480
qml: ueImageWrapper.width:132.92307692307693
qml: ueImageWrapper.width:133.83783783783784
BaCaRoZzo's suggestion works, but I'm also a bit unsure about why it behaves the way it does. If you take a simpler example:
import QtQuick 2.6
import QtQuick.Window 2.2
import QtQuick.Layouts 1.0
import QtQuick.Controls 1.0
Window {
visible: true
width: 800
height: 800
Shortcut {
sequence: "Ctrl+Q"
onActivated: Qt.quit()
}
Item {
id: boundary
width: 400
height: 400
anchors.centerIn: parent
RowLayout {
anchors.fill: parent
Rectangle {
Layout.fillWidth: true
Layout.fillHeight: true
color: "steelblue"
}
Rectangle {
id: rect
Layout.fillWidth: true
Layout.fillHeight: true
color: "salmon"
visible: false
}
}
}
Rectangle {
anchors.fill: boundary
color: "transparent"
border.color: "black"
}
Button {
text: "Toggle visibility"
onClicked: rect.visible = !rect.visible
}
}
The second rectangle starts off being invisible, and is then shown/hidden by clicking the button. However, when it starts off as invisible, it never gets a size once shown. On the other hand, if it starts off visible, then it gets half the width of the layout.
If you read the documentation carefully, it doesn't say that it's necessary to set a preferredWidth/preferredHeight if you just want to make an item fill the available space. For that reason, it seems like a bug in how layouts handle initial visibility of their items. I'd suggest filing a bug report.

RowLayout ignores Layout.minimumWidth

The text and text2 should be properly elided (show three dots when space is not enough to cover whole string) when the window is too small. The Layout.preferredWidth is set to be text.implicitWidth with some addition for padding, but i even set the Layout.minimumWidth, so the text can be ellided when the space is not enough. It seems that the RowLayout is ignoring the Layout.minimumWidth and keeps the Layout.preferredWidth, so the text has still width of Layout.preferredWidth and is never elided. What's wrong?
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
ApplicationWindow {
id: window
visible: true
width: 640
height: 480
title: qsTr("Hello World")
contentItem.minimumWidth: 50
RowLayout {
id: ntoolbarline
anchors.fill: parent
Rectangle {
color: "red"
Layout.preferredWidth: text.implicitWidth + 40
Layout.preferredHeight: 25
Layout.minimumWidth: 25
Layout.minimumHeight: 25
Layout.maximumWidth: text.implicitWidth + 40
Text {
id: text
anchors.centerIn: parent
text: "Foooooooo"
elide: Text.ElideRight
width: parent.width - 40
renderType: Text.NativeRendering
}
}
Rectangle {
color: "red"
Layout.preferredWidth: text2.implicitWidth + 40
Layout.preferredHeight: 25
Layout.minimumWidth: 25
Layout.minimumHeight: 25
Layout.maximumWidth: text2.implicitWidth + 40
onWidthChanged: console.log("layout item width: " + width) // only one output when app started
Text {
id: text2
anchors.centerIn: parent
text: "Baaaaaaaar"
elide: Text.ElideRight
width: parent.width - 40
renderType: Text.NativeRendering
}
}
Item {
id: spacer
Layout.fillWidth: true
onWidthChanged: console.log("spacer width: " + width) // outputs whenever the window is resized
}
}
}
You have two main problems here:
fillWidth is not defined
Text is centerIn the parent Rectangle
Without 1. the Rectangles cannot grow or shrink inside the desired constraints. By making use of 2. the Text element as no specific constraints on its size and borders and thus Text cannot correctly check that an elide is required. The correct way to go is to use fill and setting alignments via the verticalAlignment and horizontalAlignment of Text.
The final revisited code looks like the following:
import QtQuick 2.5
import QtQuick.Controls 1.4
import QtQuick.Layouts 1.1
ApplicationWindow {
id: window
visible: true
width: 640
height: 480
minimumWidth: 50
title: qsTr("Hello World")
RowLayout {
id: ntoolbarline
anchors.fill: parent
Rectangle {
color: "red"
Layout.fillWidth: true
Layout.preferredWidth: text.implicitWidth + 40
Layout.preferredHeight: 25
Layout.minimumWidth: 25
Layout.maximumWidth: text.implicitWidth + 40
Text {
id: text
anchors.fill: parent
text: "Foooooooo"
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
renderType: Text.NativeRendering
}
}
Rectangle {
color: "red"
Layout.fillWidth: true
Layout.preferredWidth: text.implicitWidth + 40
Layout.preferredHeight: 25
Layout.minimumWidth: 25
Layout.maximumWidth: text.implicitWidth + 40
Text {
id: text2
anchors.fill: parent
text: "Baaaaaaaar"
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
renderType: Text.NativeRendering
}
}
Item {
id: spacer
Layout.fillWidth: true
}
}
}

QML Row element refuses to work

I know I should be using Row, Column etc. rather than items anchored by ID to make my code simpler and easier to read. But they refuse to work most of the time. For example, in this case:
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Layouts 1.1
ListView {
id: listView
anchors.fill: parent
topMargin: spacing
anchors.leftMargin: spacing
anchors.rightMargin: spacing
clip: true
spacing: 0.5 * pxPermm
model: SqlQueryModel {}
delegate: Rectangle {
id: delegateItem
color: "white"
height: 14 * pxPermm
width: listView.width
clip: true
Row {
id: row
anchors.fill: delegateItem
spacing: pxPermm
Image {
height: row.height
width: height
source: "qrc:/resources/ryba.jpg"
fillMode: Image.PreserveAspectCrop
}
Item {
id: textItem
height: row.height
Label {
anchors.left: textItem.left
anchors.top: textItem.top
text: nazov
font.bold: true
}
Label {
anchors.left: textItem.left
anchors.bottom: textItem.bottom
text: cas
}
}
}
}
}
This shows two Labels on the top of an Image in the delegate of list view. Not two labels to the right of the image, as you would expect. However, this code works:
import QtQuick 2.4
import QtQuick.Controls 1.3
import QtQuick.Layouts 1.1
ListView {
id: listView
anchors.fill: parent
topMargin: spacing
anchors.leftMargin: spacing
anchors.rightMargin: spacing
clip: true
spacing: 0.5 * pxPermm
model: SqlQueryModel {}
delegate: Rectangle {
id: delegateItem
color: "white"
height: 14 * pxPermm
width: listView.width
clip: true
Row {
id: row
anchors.fill: delegateItem
spacing: pxPermm
Image {
height: row.height
width: height
source: "qrc:/resources/ryba.jpg"
fillMode: Image.PreserveAspectCrop
}
Label {
text: nazov
font.bold: true
}
}
}
}
Of course I need to show more than one label in the delegate. What am I missing here?
It turns out that Item has zero width by default. The code works properly after the width is set:
Item {
id: textItem
height: row.height
width: childrenRect.width
// labels etc
}