ShaderEffectSource doesn't respect scale of source item - qt

I use ShaderEffectSource to cache some UI items which works fine if the scale property of the source item is 1.0. If I change the scale of source item to something else, ShaderEffectSource doesn't respect it :
Row {
spacing: 100
Rectangle {
id: rect
scale: 2.0
color: "blue"
width: 50
height: 50
Text {
text: "TEST"
color: "white"
anchors.centerIn: parent
}
}
ShaderEffectSource {
sourceItem: rect
live: true
width: rect.width
height: rect.height
// hideSource: true
}
}
If I apply the same scale value to ShaderEffectSource then it just interpolates it which results in lower resolution copy:
So the question is, how can I get a properly scaled render of the source item ?

The reason is because scale property does not affect height and width properties.
If you want to get the correct size for your ShaderEffectSource, you need to multiply with the scale value:
ShaderEffectSource {
sourceItem: rect
live: true
width: rect.width * rect.scale
height: rect.height * rect.scale
}
P.S.: Scale property scales from item's origin. You're going to have a difference between you ShaderEffectSource top and your rect top. Using a RowLayout may position correctly both your elements.

Related

QML: Problems with setting the size of the button in a layout

I have this app page in qml:
Image {
source: "file:///C:/Users/image.jpg"
fillMode: Image.PreserveAspectCrop
Rectangle {
width: parent.width/3
height: parent.height/3
anchors.centerIn: parent
radius: 5
ColumnLayout {
width: parent.width * 0.5
height: parent.height * 0.5
anchors.centerIn: parent
//some components here ...
Button {
//width: 100 nothing changes in the app
Layout.alignment: Qt.AlignHCenter | Qt.AlignBottom
style: ButtonStyle {
background: Rectangle {
color: "blue"
radius: 15
//width: 100 nothing changes in the app
}
label: Text {
text: qsTr("Button")
color: "white"
}
}
}
}
}
}
Now I'm trying to set the size (width and height) of the button, so that depends on the size of the parent (layout), something like width: parent * 0.4. I probably tried every possible position of the width statement in the code, but when I run the app the size of the button never changes. I also tried to set the size to a specific number, not to bind it to the parent, still nothing.
So what could be the problem here? Where and how should be the button size defined so it's binded to its parent layout size?
Have you tried the suggestion from #folibis? I'm guessing this is a similar issue to the question here. In that example, elements inside of a Layout were not responding to the width and height parameters. Setting Layout.preferredWidth and Layout.preferredHeight seemed to solve the issue. Please refer to the documentation provided in that answer.
You can still bind to the parent's properties, for example
Layout.preferredWidth: parent.width * 0.4

How to implement curved scrollview in qml?

How to get the look of curved Scroll bar/scroll view as shown below in QML with Label or TextArea?
Basically this application is not a touch application.
Environment, Qt 5.7.0 in Linux.
You can use PathInterpolator from Controls.2. The example below is some Slider modification, you can adopt it for your needs:
import QtQuick 2.9
import QtQuick.Controls 2.2
ApplicationWindow {
id: mainWindow
visible: true
width: 400
height: 400
Path {
id: myPath
startX: 0; startY: 20
PathCurve { x: 100; y: 40 }
PathCurve { x: 200; y: 10 }
PathCurve { x: 300; y: 40 }
}
Slider {
id: control
width: 300
height: 50
anchors.centerIn: parent
background: Rectangle {
anchors.fill: parent
color: "orange"
Canvas {
anchors.fill: parent
contextType: "2d"
onPaint: {
context.strokeStyle = "MediumPurple";
context.path = myPath;
context.stroke();
}
}
PathInterpolator {
id: motionPath
path: myPath
progress: control.visualPosition
}
}
handle: Rectangle {
width: 30
height: 30
radius: 15
color: "DodgerBlue"
x: motionPath.x - 15
y: motionPath.y - 15
}
}
}
You can use a Flickable to have your view. To this Flickable you attatch a ScrollBar which you can style.
To style this ScrollBar is a bit tricky, for some of its properties are bullshit.
The position-property, which is documented as
This property holds the position of the scroll bar, scaled to 0.0 - 1.0.
will never reach 1.0 unless, the handles size is 0. You don't really have the ability to set the size of the handle, though. It will be automatically resized. So if you don't want to have a handle that fills the width of the ScrollBar entirely, you need to use a Item as a base and add a the visual inside this, so you have the sovereignity again.
All together, it might look like this:
Flickable {
anchors.fill: parent
contentWidth: width
contentHeight: mainWindow.height * 10
Rectangle {
width: 640
height: mainWindow.height * 10
gradient: Gradient {
GradientStop { color: 'orchid'; position: 0 }
GradientStop { color: 'orange'; position: 1 }
}
}
ScrollBar.vertical: ScrollBar {
id: scrollBar
width: 50
contentItem: Item {
// This will deal with the bullshit of the position. Imperfect, as I do not consider any margins/paddings
property real normalizedPosition: scrollBar.position * (scrollBar.height / (scrollBar.height - height))
Rectangle {
// Draw the curve by defining a function for x in dependance of the position.
x: Math.sin(Math.PI * parent.normalizedPosition) * 40
width: 10
height: parent.height // I use the default height, so it
// really goes from top to bottom.
// A smaller height means, you should
// also alter the y value to have a
// more natural behavior.
radius: 5
color: 'green'
Text {
text: parent.parent.normalizedPosition
}
}
}
}
}

For QML, why LayoutMirroring doesn't work in Slider?

Today I tried the Slider in QtQuick.Controls, my slider is left to right, I want to set my slider as from right to left by using LayoutMirroring.enabled, at last I found I cann't inverted the slider.
Here is my little demo code, so how can we invert a slider?
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Slider{
id:test
value: 0.2
width:400
LayoutMirroring.enabled: true
}
}
If you use the Slider from QtQuick.Controls 2.x - at least for me - it works like a charm. If you use the Slider from QtQuick.Controls 1.x it does not.
From the documentation:
Keep in mind, however, that mirroring does not affect any positioning that is defined by the Item x coordinate value, so even with mirroring enabled, it will often be necessary to apply some layout fixes to support the desired layout direction.
The QtQuick.Controls 1.x-Slider however uses a largely coordinate based implementation and has no further precautions to support the LayoutMirroring.
However the Sliders layout is usually symetrically, so all you need to do is to map the values like from (0,1) to (1,0). This should be a easy task to a developer.
import QtQuick.Controls 1.3
import QtQuick.Controls.Layouts 1.3
import QtQuick.Controls.Private 1.3 // Needed for a mysterious value from the original, now mirrored style.
Slider {
y: 40
id: sli
width: parent.width
minimumValue: 50
maximumValue: 100
property real mirroredValue: maximumValue - value + minimumValue
// Invert style
style: SliderStyle {
groove: Item {
property color fillColor: "#49d"
anchors.verticalCenter: parent.verticalCenter
// Whatever TextSingleton is. You need to import QtQuick.Controls.Private 1.x for it.
implicitWidth: Math.round(TextSingleton.implicitHeight * 4.5)
implicitHeight: Math.max(6, Math.round(TextSingleton.implicitHeight * 0.3))
Rectangle {
radius: height/2
anchors.fill: parent
border.width: 1
border.color: "#888"
gradient: Gradient {
GradientStop { color: "#bbb" ; position: 0 }
GradientStop { color: "#ccc" ; position: 0.6 }
GradientStop { color: "#ccc" ; position: 1 }
}
}
Item {
clip: true
x: styleData.handlePosition // let the fill-stuff start at the handle position...
width: parent.width - styleData.handlePosition // and end at the end of the groove.
height: parent.height
Rectangle {
anchors.fill: parent
border.color: Qt.darker(fillColor, 1.2)
radius: height/2
gradient: Gradient {
GradientStop {color: Qt.lighter(fillColor, 1.3) ; position: 0}
GradientStop {color: fillColor ; position: 1.4}
}
}
}
}
}
}
If you wan't to set the value of your slider, you need to install a bidirectional binding between mirroredValue and value.
I had a similar problem. My slider was vertical with values increasing from bottom to the top. I wanted them to increase from top to bottom. I accomplished it using rotation. I think that you could have solved your problem like this:
Slider {
id: test
value: 0.2
width: 400
rotation: 180 // This should make the slider right-to-left
}

Is there any way to specify different radii for different corners

Can anyone help me how to round only one corner of a rectangle like shown in attached pic where red rectangle is my child rectangle.
Actually, I have a rectangle where all four corners rounded(radius 10). Now, i want to draw a new rectangle inside this and expecting only that particular corner should be rounded who touches the parent's round corner.
Rectangle
{
id: parent
radius: 10
width: 168
height: 168
visible: true
color: "black"
Rectangle
{
id: child
width: 100
height: 40
color: "red"
}
}
I tried to do this with adding clip property in child but nothing happened.
Here is a simple example.
It is rounded in the upper left corner, but is easily adjusted to any other corner. Only one corner is supported in this solution, but it might be enough for you?
More corners are little more complex, so ask again if you would need those aswell.
Rectangle {
anchors.centerIn: parent
id: root
radius: 20
width: 300
height: 300
Rectangle {
id: clipper
width: 100
height: 100
color: 'transparent'
clip: true
Rectangle {
id: clipped
width: parent.width + radius
height: parent.height + radius
radius: root.radius
color: 'red'
}
}
}
Not with the stock Rectangle:
The same radius is used by all 4 corners; there is currently no way to
specify different radii for different corners.
In C++ you could specify a horizontal and vertical radius, but still not per-corner radius. If you want such functionality, you will have to implement your own QQuickItem with the geometry node and all.
The result you want to achieve in the image could also be achieved with clipping, however unfortunately, in QML clipping only works for the item's rectangle, not the actual item geometry.
It will be easiest to achieve the desired effect using a BorderImage element. It enables to specify a different sub-image for every corner:
It is possible using Shape item as below:
Shape {
id: advancedShape
width: 100; height: 40
vendorExtensionsEnabled: true
layer.enabled: true
layer.samples: 4
layer.smooth: true
// set following properties to specify radius
property real tlRadius: 0.0
property real trRadius: 15.0
property real brRadius: 0.0
property real blRadius: 0.0
ShapePath {
strokeColor: "transparent"
fillColor: "red"
startX: 0; startY: advancedShape.tlRadius
PathArc {
x: advancedShape.tlRadius; y: 0
radiusX: advancedShape.tlRadius; radiusY: advancedShape.tlRadius
useLargeArc: false
}
PathLine {
x: advancedShape.width - advancedShape.trRadius; y: 0
}
PathArc {
x: advancedShape.width; y: advancedShape.trRadius
radiusX: advancedShape.trRadius; radiusY: advancedShape.trRadius
useLargeArc: false
}
PathLine {
x: advancedShape.width; y: advancedShape.height - advancedShape.brRadius
}
PathArc {
x: advancedShape.width - advancedShape.brRadius; y: advancedShape.height
radiusX: advancedShape.brRadius; radiusY: advancedShape.brRadius
useLargeArc: false
}
PathLine {
x: advancedShape.blRadius; y: advancedShape.height
}
PathArc {
x: 0; y: advancedShape.height - advancedShape.blRadius
radiusX: advancedShape.blRadius; radiusY: advancedShape.blRadius
useLargeArc: false
}
PathLine {
x: 0; y: advancedShape.tlRadius
}
}
}
and result will be as this:
NOTE The builtin Rectangle has more performance than Shape, but I recommend Shape over masking because it works on any environment.
NOTE 2 I think the most true way in production is using BorderImage as #dtech suggested IF the radius is known and you don't need to change radius dynamically.
Created this from a bunch of rectangles. Two big rectangles and 4 smaller optionally rounded squares. This way you can also make different radii for each corner, not only turning them on and off. You just need to make sure that you don't want a too big rounding, because then the rounded rect would stick out.
Rectangle {
id: clipper
width: 10
height: 10
color: "transparent"
clip: true
Rectangle {
id: clipped
width: 30
height: 30
radius: 8
color: "red"
}
}

What is the difference between Row and RowLayout?

This works as intended with Row, but not with RowLayout. Why? What is the difference between the two?
ApplicationWindow {
title: "Testing"
width: 640
height: 480
//RowLayout {
Row {
anchors.fill: parent
Rectangle {
id: rect1
width: parent.width * 0.3
height: parent.height
color: "blue"
}
Rectangle {
height: parent.height
width: parent.width * 0.7
color: "red"
}
}
}
Row is a Item Positioner. Positioner items are container items that manage the positions of items in a declarative user interface.
RowLayout is part of Qt Quick Layouts. They manage both the positions and the sizes of items on a declarative user interface, and are well suited for resizable user interfaces.
Your code with RowLayout should look like this:
RowLayout{
anchors.fill: parent
spacing: 0
Rectangle{
Layout.fillHeight: true
Layout.preferredWidth: parent.width * 0.3
color: "blue"
}
Rectangle{
Layout.fillHeight: true
Layout.fillWidth: true
color: "red"
}
}
I think
Row is a container which grows the size based on the children of Row, making them line up as a row, so the children of it shall have size.
RowLayout is the wrapper of its children, giving them the ability of row positioning and resizing based on the size of RowLayout, so RowLayout shall have its own size to help the children to position and resize.

Resources