Qt Quick Window/Frame with Inner Shadow flickers while resizing - linux

When I resize a Qt Quick ApplicationWindow that contains a Frame with an InnerShadow, I see flickering and visual artifacts. The same is not true when I either do not replace the default border or if I use a simple rectangle for the Frame object.
I tested this on my laptop that runs a 64-bit Arch Linux. It has an Nvidia GTX 1060 Max Q graphics card and an integrated Intel graphics card. I ran the code both with and without bumblebee.
Any way to work around or eliminate this flickering? It is pretty bad. My code and some screen-grabs are as below
EDIT: I have tried setting AA_ShareOpenGLContexts and AA_UseOpenGLES (and its software/desktop variants) attributes with no luck.
UPDATE: I have created an issue here: https://bugreports.qt.io/browse/QTBUG-81519, but I am still hoping someone can devise a workaround.
test.qml
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtGraphicalEffects 1.14
ApplicationWindow{
id: main
width: 2*screen.width/3
height: 2*screen.height/3
title: "Test ApplicationWindow"
color: activeColorPalette.window
visible:true
SystemPalette {
id: activeColorPalette
colorGroup: SystemPalette.Active
}
Frame{
anchors.fill: parent
anchors.margins: 10
background: Item{
id: root
anchors.fill: parent
Rectangle{
anchors.fill: parent
anchors.margins: 1
radius: 16
color: activeColorPalette.window
}
InnerShadow {
anchors.fill: root
horizontalOffset: 0
verticalOffset: 0
source: root
radius: 16
color: activeColorPalette.shadow
spread: 0.6
samples: 32
cached: true
fast:true
}
}
}
}
Window without flickering or artifacts
Window with flickering/visual artifacts while resizing

I found a workaround to eliminate the visual artifacts during resizing.
In my problem code, the InnerShadow used an Item QML type as the source, which is transparent by default and contained a grey Rectangle that I added within it. The visual distinction between the transparent source Item and the smaller child Rectangle inside it is what the InnerShadow uses to compute the shadow gradient within. The end result was a decorative shadow border. However, resizing the application resulted in ugly visual artifacts that would sometimes stay. Note: Changing the outer Item into a transparent Rectangle had no discernible effect.
But when I encapsulated the grey innermost rectangle into another transparent component like
Item {transparent Rectangle {grey inner Rectangle} }
or like
Rectangle{transparent Rectangle{grey inner Rectangle}}
in addition to setting the middle transparent Rectangle as the source for the InnerShadow, the visual artifacts are eliminated. Below is the working code for test_workaround.qml that you can compare to the test.qml above.
test_workaround.qml
import QtQuick 2.14
import QtQuick.Controls 2.14
import QtGraphicalEffects 1.14
ApplicationWindow{
id: main
width: 2*screen.width/3
height: 2*screen.height/3
title: "Test ApplicationWindow"
color: activeColorPalette.window
visible:true
SystemPalette {
id: activeColorPalette
colorGroup: SystemPalette.Active
}
Frame{
anchors.fill: parent
anchors.margins: 10
background: Item{
id: root
anchors.fill: parent
Rectangle{
id: middleRect
anchors.fill: parent
color: "transparent"
Rectangle{
id: innerRect
anchors.fill: parent
anchors.margins: 1
radius: 16
color: activeColorPalette.window
}
}
InnerShadow {
anchors.fill: root
horizontalOffset: 0
verticalOffset: 0
source: middleRect
radius: 16
color: activeColorPalette.shadow
spread: 0.6
samples: 32
cached: true
fast:true
smooth:true
}
}
}
}

Related

how to remove black background in TweenMax script

i using TweenMax and pixi.js
codepen.io/nimaina/pen/aPERKO
how to remove black background?
Well the black background that you see is the default PIXI.Application setup.
Default width: 800
Default height: 600
Default backgroundColor: 0x000000 (black)
Basically there are two options, that I see, to avoid the black background.
Option 1: use exact dimensions for width and height
I see the dimensions of greensock.png are 538x173.
var app = new PIXI.Application( {
view: document.querySelector("#canvas"),
width: 538,
height: 173
});
Option 2: set transparent:true and make the background transparent
var app = new PIXI.Application( {
view: document.querySelector("#canvas"),
transparent: true
});

GridLayout with scaled images has huge row spacing

I have a simple "dialog" in qml where the user is supposed to select one image. Images are scaled-down and shown in a GridLayout inside ScrollView. Images should be 1/2 width of the scrollview, there will be descriptions next to it.
What I see is that the vertical spacing is huge and it does not change with resizing the window. It actually seems that the spacing corresponds to full-size (unscaled) images.
The issue changes when I set Layout.preferredHeight: 100 (for example), but then again the spacing is there should the images be smaller than that, and don't grow beyond 100px in height. I would like to solve this without supposing any absolute sizes.
How to fix that?
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
ApplicationWindow{
visible: true
id: root
width: 600
height: 1200
ScrollView {
id: scroll
anchors.fill: parent
ListModel{
id: demosModel
ListElement{ src:"01.jpg"; }
ListElement{ src:"02.jpg"; }
ListElement{ src:"03.jpg"; }
ListElement{ src:"04.jpg"; }
}
GridLayout{
anchors.fill: parent
columns: 1
rowSpacing: 10
Repeater{
model: demosModel
Image {
source: "assets/"+src;
Layout.preferredWidth: .5*scroll.width;
fillMode: Image.PreserveAspectFit;
}
}
}
}
}
In your example:
Image { source: "assets/"+src } will use the real size of the images.
Layout.preferredWidth: .5*scroll.width will limit the width of the area in which the image will be displayed. So the big images will be displayed with a width of 300px (.5*scroll.width) but will conserve their height.
fillMode: Image.PreserveAspectFit; will scale the image uniformly to fit in the 300px. The proportions of the images are now visually OK but the value of the height property remains the same and this is this value which will be used by the layout.
So I think the solution is to force the width (the height will be recalculated) of the element via the sourceSize property:
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.3
ApplicationWindow{
id: root
width: 600
height: 1200
visible: true
ScrollView {
id: scroll
anchors.fill: parent
ListModel{
id: demosModel
ListElement{ src:"01.jpg"; }
ListElement{ src:"02.jpg"; }
ListElement{ src:"03.jpg"; }
ListElement{ src:"04.jpg"; }
}
GridLayout{
anchors.fill: parent
columns: 1
rowSpacing: 10
Repeater{
model: demosModel
Image {
source: "assets/" + src;
Layout.preferredWidth: .5 * scroll.width;
// Qt documentation: "If only one dimension of the size is set to greater
// than 0, the other dimension is set in proportion to preserve the
// source image's aspect ratio. (The fillMode is independent of this.)"
// fillMode: Image.PreserveAspectFit;
sourceSize.width: Layout.preferredWidth
}
}
}
}
}

QML ignores width and height when setting anchors

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.

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.

Resources