Binding expression + animation causes object to disappear and reappear randomly - qt

I have a visual tree of the following object:
Row {
spacing: 4
y: 1
U_Icon {
width: 48
height: 48
scale: (activeo === main.object ? 1.18 : 1) * (main.expand ? 1 : 0.75)
Behavior on scale { SpringAnimation { spring: 10; damping: 0.2; duration: 100 } }
color: activeo == object ? "white" : "#262626"
anchors.verticalCenter: parent.verticalCenter
}
Column {
spacing: -10
Text {
text: object.type + "type"
font.pointSize: 10
font.family: sysfont
}
Text {
text: "name"
font.pointSize: 20
font.family: sysfont
font.italic: true
font.letterSpacing: -1
}
}
}
The scale of the icon depends on whether the current object is selected or expanded. Expanding causes the object to draw its children objects. However, on re-expanding after contracting, depending on the tree structure, children objects are missing their text, which mysteriously reappears when another object is selected or created. Selecting another object might cause one, several or all missing texts to appear, the same goes for creating another object. When the tree is expanded, the texts are there for an instant, after which they disappear.
I made a few observations:
if the binding for the scale is only either of the two expressions without the other, the problem does not manifest
if the animation is removed, the problem does not manifest
interfacing the icon scale as an alias property of the row in order to move the binding out of the component and to the place it is instantiated has no effect, the problem persist
breaking down the binding expression by adding dedicated activefactor and expandfactor property for each expression and reducing the scale binding to activefactor * expandfactor has no effect, the problem persists
refactoring the binding expression to a code block with a return statement (sometimes that helps when single liners fail) has no effect, the problem persists
Here is an illustration of what's going on:
1 - the tree builds OK
2 - the tree is collapsed
3 - the tree is expanded again, the text flashes for a moment and disappears
4 - clicking arbitrary object causes all text to reappear
Any ideas what's going on? Yet another bug or am I missing something? Why would a slightly more complex expression cause the column with the text to disappear? It is not a problem of the changing scale in particular, since both expressions change it and both work on their own.
Note that the text is still there, just not being rendered by the scene-graph, that is evident from the size of the light-grey rounded rectangle which is sized to match the row width. The scale of the icon itself is evaluated and displayed property, but for some reason causes the text to disappear.
EDIT: Another curious observation, if the text column is replaced by a common rectangle, the bug does not manifest. If the column is wrapped inside a rectangle the same width as the column, but only as high as the small text, this causes only the large text to go missing:
This adds more weight to my suspicion that this is a bug in the scene-graph, and wrapping it in a rectangle forces the renderer to update only that portion of the missing text. Note that the rectangle is not clipping the column. Furthermore, if the rectangle color is set to #00000000, that is fully transparent, the text is missing again, the scene graph disregards it, and thus there is nothing to force the update of the text part. As expected, wrapping in an Item is no help either, nor is using text directly, without the column. If the rectangle is extended further down, it cuts through the big text, as a result, only the upper half of the big text is visible. Even the tiniest amount of transparency in the rectangle causes the text to go missing, even if the rectangle is 99.99% opaque. Only a 100% opaque rectangle forces the visibility of the text.
I have tested it with latest Qt 5.7 on windows 7 x64 (stock x86 qt build + custom x64 opengl static) and linux x64 (using the mesa drivers).

Related

QML/Qt: Make displayed text as large as possible depending on the parent containing it

I am trying to make a very simple KDE-Plasma Widget where only a certain number is displayed. I want to make this displayed number have a font size as large as possible depending on the parent containing it.
Here is what it looks right now:
As you can see, the text inside has a lot of space around it. What I actually want it to be is something like the "Date And Time" Widget found in KDE Plasma (my widget is right next to it for comparison):
Here, the time displayed has much lesser space around it while also auto-resizing whenever the panel height is changed.
Here is what the current code looks like:
import QtQuick 2.6
import QtQuick.Layouts 1.0
import org.kde.plasma.components 2.0 as PlasmaComponents
import org.kde.plasma.plasmoid 2.0
Item {
id: main
anchors.fill: parent
Layout.minimumWidth: units.iconSizes.large
Layout.minimumHeight: units.iconSizes.large
Plasmoid.preferredRepresentation: Plasmoid.fullRepresentation
PlasmaComponents.Label {
id: display
anchors {
fill: parent
margins: Math.round(parent.width * 0.1)
}
verticalAlignment: Text.AlignVCenter
horizontalAlignment: Text.AlignHCenter
text: foobar
font.pixelSize: 1000;
minimumPointSize: theme.smallestFont.pointSize
fontSizeMode: Text.Fit
font.bold: true
}
Timer {
some stuff
}
}
I tried looking into the code of the above Date and Time widget and wrote down the exact same layouts/controls (which is what you are seeing in the above code) with the same positioning/styling properties and yet I get a lot of space around my text/or the font size continues to remain small.
I tried your code and it resized the font correctly. For the spacing around the text, there are two points:
The spacing on the left and right is easily controlled by adjusting the margins value that you are using. For less space, try Math.round(parent.width * 0.05).
The spacing on the top and bottom is larger because the shape of your parent object is square, while the shape of the text is rectangular. In order to make the text fit the height of the square without exceeding the width of the square, the text would not just need to resize, it would need to be stretched vertically. But QML does not have an easy way to do that, and I doubt that's really what you want anyway.
EDIT:
And if you do want font stretching, I'll point you to this answer.
Thanks to #JarMan's input I was able to realize that my text was being rendered in small font because of lack of space due to the root (item) element being square in shape.
I have now figured that to change the layout sizes of the root element inside the KDE-Plasma panel, one needs to mess with Layout.preferredWidth and Layout.preferredHeight.
Here is what I did:
item {
.
.
Layout.preferredWidth: 150 * units.devicePixelRatio
Layout.preferredHeight: 50 * units.devicePixelRatio
.
.
}
Note: the 150 and 50 values aren't final. It basically gives an idea about the ratio at which the root element's width and height should be in (and I wanted a rectangle). It automatically resizes the inner content too as the Plasma Panel is resized.

Binding not updating when there is frame dropping in QML

I have a UI element, which appears while I do some calculation and disappears when the calculation finished. The appearing and disappearing is animated. The animation animates the item's implicitHeight from 0 to X and vice-versa. These items live in a ListView as delegates. The ListView is wrapped in an Item as the root element of this component. The implicitHeight of this root element depends on, aka is binded to the contentHeight of the ListView. The width of this root element is set where the component is used. Here you can see my explanation in code:
Item {
id: _root
implicitHeight: _listView.contentHeight
ListView {
id: _listView
width: _root.width
height: contentHeight
delegates: AnimatingItem {
// ...
}
}
}
The AnimatingItems in the code have predefined height (not necessarily the same for all). I wrote a small debug code piece which basically writes the ListView's contentHeight, childrenRect.height, height and the root item's implicitHeight to the console on a button press.
In most cases when ever I press this button to print out those values, like during a calculation when the item is present (= X) or when there is no calculation therefore the item is hidden (= 0), they all match.
In certain scenarios when I do some really heavy calculation though, when even the UI freezes/drops frames and the calculation finishes and I press the debug button all the ListView's values match (= 0), but the items's implicitHeight differs (= X). The weird thing is that the AnimatingItem's or in other words the ListView disappears thus there is no visible item, but if I anchor a Rectangle to the top of this item then it will float in the air instead of moving down as the ListView disappears.
Is it possible that if I have a really heavy calculation one or more bindings can "forget" to update due to dropping frames?
On some platforms animations don't run in a dedicated thread, but I don't think that's the case of Mac OS. So dropping frames due to lack of graphics performance should not cause skips in binding evaluations. Now if you have a CPU hotspot as a cause of the dropped frame, that's a different story. The animation is synced to the event loop rate as well as the scenegraph rate, so if your event loop is stalling, then it is simply not making the value change, which is why you don't get reevaluations.
As a rule of thumb, you shold never ever do heavy calculations in the main/gui thread. If it causes the GUI to freeze for more than 10 msec you need to offload it to a dedicated thread, and update the results asynchronously. Don't stall or block the gui thread!
Also, binding to contentHeight hasn't work as expected for me in many of the cases. What has proven to work is binding to contentItem.childrenRect.height. Also, the root item is completely redundant if it is going to be just an empty item, but even if it will have direct children, you can do that with the list view which is also an Item.
If you scale the view to the full height, I'd recommend to use a Column with a Repeater instead. A simple repeater will take advantage of all the model features and efficiencies too, so no worries there.

QML tab occasionally stretches off-screen

I have a QML-based GUI with a fixed width that uses the TabView type in several places.
On one page, I have something like this (leaving out most properties except for lateral anchors):
ColumnLayout {
MyTabsViewSubmenu { // defined below
Layout.fillWidth: true
Tab {
id: someId
title: someString
anchors.fill: parent
SomeCustomClass {
id: someId2
anchors.fill: parent
}
}
// three more tabs defined the same way, with the same anchors...
}
// another item below the tabs...
}
MyTabsViewSubmenu is something like this:
TabView {
Rectanble {
anchors.fill: parent
}
style: TabViewStyle {
// miscellaneous style stuff
}
}
One of my four tabs in the ColumnLayout above sometimes stretches off the screen when selected. As far as I can tell, there is nothing special about it compared to the other items used as tabs throughout the GUI. The layout of this tab is something like this:
Item {
MyTabsViewSubmenu {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: sibling.top
Tab {
// no anchors (see below)
SomeItem {
anchors.fill: parent
}
// ... other tabs....
}
Rectangle {
id: sibling
anchors.left: parent.left
anchors.right: parent.right
// ... stuff....
}
}
The entire page stretches off the screen: both the sub-tab content and the content in the Rectangle I've shown here as sibling.
I would suspect that possibly the missing anchors.fill: parent in the innermost Tabs might be the problem, except that sibling is not (as far as I can tell* missing any anchors, and I've never seen the tabs stretched offscreen without the sibling being stretched offscreen as well.
It seems entirely unpredictable whether the stretching occurs or the layout is done correctly. Once the layout has stretched off the screen, I can sometimes get it to correct itself by navigating away from that page and back.
I'm using Qt 5.6.1-1 on Debian 7.
EDIT: When I navigate to the "stretched" tab and the bug occurs causing the stretching, the tabs themselves at the top of the page also get "stretched" somewhat. Returning to a different tab un-stretches the tabs.
The fix
Setting Layout.maximumWidth (as per Velkan's comment) appears to resolve the issue. Additionally, it appears to make the page load faster.
Observations and testing
It's now about a week and a half since I introduced this change to the code, and the product has been heavily tested since then.
We have discovered a second component that needs Layout.maximumWidth set in order to keep from stretching off the screen, and indeed applying this fix to both the original problematic components has prevented the screen-stretching bug. So this is definitely a valid fix.
Possible root cause (i.e. groundless speculation)
I suspect that the QML engine attempts to size "Layout" objects by starting with the maximum width, then shrinking them to fit (or something like this). If the maximum width is unset, it's set to something like "infinity". Without a maximumWidth, it appears that the auto-shrinking operation sometimes fails, leaving the component stretched offscreen. I suspect that the automatic-resizing code may be impacted by some kind of nondeterminism in the order in which the sizes of different QML components are computed.

What is best way to load either Rectangle(drawn by code) or Image in Qml?

I have a Qml file with one 'Rectangle' and an 'Image'. I want to load either one based on the property set in my.cpp file.
Please help me to find a best way to do this.
Actually I could think two possible ways to do the same:
1) First approach is to have both the element (the image and rectangle), defined in the respective QML, and to control their visibility from my.cpp file. I can have a property, this property can control the visibility of either of the two. Drawback in this approach is that even though only one element has to be displayed, two will be created.
2) Second approach is that we can have two components and load either one using "Loader" depending on the property set from the my.cpp.
Ex:
'
Component
{
id:img
Image
{
id: myImage
source:currentdir + "/img_production/Separator/myImage.png"
width: 10
height: 79
}
}
Component
{
id:rect
Rectangle
{
id:re
height: 82
width: 10
color: "#FFFFFF"
}
}
Loader
{
id: itemDisplay
sourceComponent: style.flag? rect : img
anchors.fill: parent.fill
}
'
Looking for some expert suggestions.
PS: style.flag is property set by my.cpp to Qml.
In this case, where both items are simple base types, I would go for the visibility change.
Having both elements instantiated directly makes it easier to refer to them in bindings or bind to their properties.
It also means their allocation only happens once, reducing the chance of memory fragmentation
If you are worried about the image consuming too much memory while the rectangle is shown you could still make the image`s source property depend in the visiblity value, i.e. unload the image when not showing the Image element.

QML : If condition in delegate?

I'm designing a spinner list control, which displays 3 items at a time.
Its working fine as required behaviour the only issue am facing is I need the central element appearance little bigger.
The approach which I can think as of now is to have an if condition in the delegate, which on the basis of current index increases the font size.
Is the above approach is possible? Any suggestions to achieve the particular behaviour
Below is the code snippet
SpinnerData {
id: spinner
focus: true
model: 20
delegate: Text { font.pixelSize: spinner.height/4.5; text: index; height: spinner.height }
}
I don't know the details of your component but here you can see implementation of the same control in Qt Quick Components.

Resources