I wanted to create an UI similar to below images. I understand Qt Pathview helps me to move the items in an circular fashion. But I couldn't get how to create the background similar to the images with equal space between the text. I tried with rectangle (radius:360) to draw circle, but the pathview items doesn't move along the center of the rectangle-circle.
Maybe this simple example could help you with PathView:
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
visible: true
width: 400
height: 400
Item {
id: container
width: 300
height: 300
anchors.centerIn: parent
Rectangle {
anchors.fill: parent
radius: width /2
color: "orange"
Rectangle {
x: 50
y: 50
width: 200
height: 200
radius: 100
color: "white"
}
}
PathView {
anchors.fill: parent
model: 10
delegate: Rectangle {
width: 50
height: 50
radius: 25
color: "green"
}
path: Path {
startX: 150; startY: 25
PathArc {
x: 150; y: 275
radiusX: 125; radiusY: 125
direction: PathArc.Clockwise
}
PathArc {
x: 150; y: 25
radiusX: 125; radiusY: 125
direction: PathArc.Clockwise
}
}
}
}
}
Related
I'm trying to create a reusable slider. I'm having trouble to set implicit sizes correctly so that the CustomSlider includes the Slider and the Label. I would like to have a implicit size specified, but let the user set a width for the slider itself.
I tried using childrenRect but that gives me a binding loop error.
How can I have the yellow background span across all the components: the slider and the green label?
Currently:
Would like:
CustomSlider.qml
Item {
id: root
property int startval: 0
property int endval: 20
property int sliderWidth: 200
// This results in binding loop
//implicitHeight: childrenRect.height
implicitHeight: control.height + label.height
implicitWidth: sliderWidth
Rectangle {
color: "yellow"
width: root.width
height: root.height
}
Slider {
id: control
stepSize: 1
anchors.centerIn: parent
snapMode: Slider.SnapOnRelease
width: root.sliderWidth
from: root.startval
to: root.endval
handle: Rectangle {
id: handleId
x: control.visualPosition * (control.width - width)
y: (control.height - height) / 2
width: 20
height: 20
radius: 20
color: "gray"
}
background: Rectangle {
y: (control.height - height) / 2
height: 4
radius: 2
color: "green"
Rectangle {
width: control.visualPosition * parent.width
height: parent.height
color: "red"
radius: 2
}
}
}
Label {
id: label
width: 20
height: 20
text: control.value
font.pixelSize: 15
color: "black"
x: handleId.x + control.x
y: handleId.y - 20
Rectangle {
color: "green"
anchors.fill: parent
opacity: 0.3
}
}
}
Main.qml
CustomSlider {
anchors.centerIn: parent
startval: 0
endval: 10
//sliderWidth: 100
}
I usually set the Width and height based on the parent.
I set sliderWidth: parent.width/2.0 and for your green label I add TextMetrics and calculate its width based on the text that it wants to show.
import QtQuick 2.15
import QtQuick.Controls 2.15
Item {
id: root
property int startval: 0
property int endval: 0
property int sliderWidth: parent.width/2.0
// This results in binding loop
//implicitHeight: childrenRect.height
implicitHeight: control.height + label.height
implicitWidth: sliderWidth
Rectangle {
color: "yellow"
width: root.width
height: root.height
}
Slider {
id: control
stepSize: 1
anchors.centerIn: parent
snapMode: Slider.SnapOnRelease
width: root.sliderWidth
from: root.startval
to: root.endval
handle: Rectangle {
id: handleId
x: control.visualPosition * (control.width - width)
y: (control.height - height) / 2
width: 20
height: 20
radius: 20
color: "gray"
}
background: Rectangle {
y: (control.height - height) / 2
height: 4
radius: 2
color: "green"
Rectangle {
width: control.visualPosition * parent.width
height: parent.height
color: "red"
radius: 2
}
}
}
Label {
id: label
width: t_metrics.tightBoundingRect.width +4
height: t_metrics.tightBoundingRect.height +7
text: control.value
font.pixelSize: 15
color: "black"
x: handleId.x + control.x
y: handleId.y - 20
Rectangle {
color: "green"
anchors.fill: parent
opacity: 0.3
}
}
TextMetrics {
id: t_metrics
text: control.value.toString()
}
}
Updated:
in CustomSlider.qml , changed it to this code:
import QtQuick 2.15
import QtQuick.Controls 2.15
Item {
id: root
property int startval: 0
property int endval: 0
property int sliderWidth: parent.width/2.0
implicitHeight: control.height + label.height
implicitWidth: sliderWidth
Rectangle {
color: "yellow"
width: root.width +10
height: root.height +control.height + label.height + t_metrics.tightBoundingRect.height +7
Slider {
id: control
stepSize: 1
anchors.centerIn: parent
snapMode: Slider.SnapOnRelease
width: root.sliderWidth
from: root.startval
to: root.endval
handle: Rectangle {
id: handleId
x: control.visualPosition * (control.width - width)
y: (control.height - height) / 2
width: 20
height: 20
radius: 20
color: "gray"
}
background: Rectangle {
y: (control.height - height) / 2
height: 4
radius: 2
color: "green"
Rectangle {
width: control.visualPosition * parent.width
height: parent.height
color: "red"
radius: 2
}
}
}
Label {
id: label
width: t_metrics.tightBoundingRect.width +4
height: t_metrics.tightBoundingRect.height +7
text: control.value
font.pixelSize: 15
color: "black"
x: handleId.x + control.x
y: handleId.y /2 + 4
Rectangle {
color: "green"
anchors.fill: parent
opacity: 0.3
}
}
TextMetrics {
id: t_metrics
text: control.value.toString()
}
}
}
This makes your text label shows inside the yellow rectangle and in main.qml I add one Row with labels and spinboxes for the test.
If you want that user to set sliderWidth or startval and endval and then show him Slider you need to create that object dynamically.
and if you want to be displayed in the Column and don't overlap you need ColumnLayout.
If you want to scroll them then you need to use ScrollView.
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtQuick.Layouts 1.15
Window {
width: 660
height: 480
visible: true
title: qsTr("Hello World")
ScrollView {
width: parent.width
height : parent.height
contentWidth: slidersColumn.width
contentHeight: slidersColumn.height
clip : true
ColumnLayout {
id: slidersColumn
anchors.fill: parent
spacing:50
}
}
function addSlider(sliderWidth,startval,endval) {
var obj = Qt.createComponent("CustomSlider.qml");
var slider = obj.createObject(slidersColumn);
slider.startval=startval;
slider.endval=endval;
slider.sliderWidth=sliderWidth;
}
Row
{
x: 0
y: 5
width: parent.width
height: 30
Label {
id: lbl_slider_width
text: qsTr(" Slider width ")
}
SpinBox {
id: spinBox_slider_width
editable: true
from:0
to:parent.width
}
Label {
id: lbl_startval
text: qsTr(" Startval ")
}
SpinBox {
id: spinBox_startval
editable: true
from:0
to:parent.width
}
Label {
id: lbl_endval
text: qsTr(" Endval ")
}
SpinBox {
id: spinBox_endval
editable: true
from:0
to:parent.width
}
Button {
id: button
text: qsTr(" Create Slider")
onClicked:
{
addSlider(spinBox_slider_width.value,spinBox_startval.value,spinBox_endval.value)
}
}
}
}
The result is:
Is there a way to have a Rectangle with one side rounded edges and also a border in Qt without using the Canvas.
Something like below.
I did try below code and I am able to create the rounded corner on one side.
import QtQuick 2.5
import QtQuick.Window 2.2
Window {
width: 200
height: 200
visible: true
Item {
width: 100
height: 50
opacity: 0.5
layer.enabled: true
anchors.centerIn: parent
Rectangle {
color: "blue"
radius: 10
anchors.fill: parent
}
Rectangle {
color: "blue"
anchors.fill: parent
anchors.leftMargin: 10
}
}
}
With above code I am able to get the one side rounded corners but when I add border then I see overlapping borders.
Is there a clean way of doing this in Qml?
I can think of two ways to do that.
Not the "cleanest" way, but probably the simplest performance-wise. You can keep using the code you have above, but just draw another non-bordered rectangle that covers up the extra border line that you are seeing.
property int borderWidth: 4
Item {
width: 100
height: 50
opacity: 0.5
layer.enabled: true
anchors.centerIn: parent
Rectangle {
id: roundCorners
color: "blue"
radius: 10
border.width: borderWidth
anchors.fill: parent
}
Rectangle {
id: squareCorners
color: "blue"
border.width: borderWidth
anchors.fill: parent
anchors.leftMargin: 10
}
Rectangle {
anchors.left: squareCorners.left
anchors.verticalCenter: squareCorners.verticalCenter
width: borderWidth
height: squareCorners.height - borderWidth * 2
color: "blue"
}
}
You can use QML's Shape object and use a ShapePath to define it. The docs can be found here.
Shape {
ShapePath {
strokeWidth: 4
strokeColor: "black"
fillColor: "blue"
PathLine { ... }
PathLine { ... }
PathLine { ... }
PathArc { ... }
}
}
Is it possible in QML, maybe using shader effects with layers, to create an item that makes another item (with a higher z index) visible only when the two layers overlap? I've been messing aroud with OpacityMask and ThresholdMask but have been unable to figure it out. The effect I'm looking for in the context of the example below would be if the the black circle was only visible when the two red squares are under it:
current:
desired:
Some key points are that the bottom layer (red squares) must be moveable (OpacityMask doesn't seem to let you drag the maskSource) and the bottom layer needs to also be able to contain other elements within it that the black circle responds to. Any guidance towards the right things to learn in order to achieve this would be appreciated. Here is the QML for the red squares and black circle thing. The red squares are draggable as one element:
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Layouts 1.12
import QtGraphicalEffects 1.12
Window {
id: main_window
visible: true
width: 1500
height: 1000
title: qsTr("Hello World")
Item {
width: main_window.width
height: main_window.height
LinearGradient {
anchors.fill: parent
start: Qt.point(0, 0)
end: Qt.point(main_window.width, 0)
gradient: Gradient {
GradientStop { position: 0.0; color: "#003cff" }
GradientStop { position: 1.0; color: "#9afff9" }
}
}
}
Rectangle {
id: sfg
width: 175
height: 75
color: 'transparent'
RowLayout {
width: parent.width
height: parent.height
spacing: 25
Rectangle {
Layout.preferredWidth: 75
Layout.fillWidth: false
Layout.fillHeight: true
color: 'red'
}
Rectangle {
Layout.preferredWidth: 75
Layout.fillWidth: false
Layout.fillHeight: true
color: 'red'
}
}
MouseArea {
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
drag {
target: sfg
}
}
}
Rectangle {
id: mask
color: 'black'
x: 400
y: 200
width: 100
height: 100
visible: true
opacity: 1
radius: 50
}
}
Like this?
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Layouts 1.12
import QtGraphicalEffects 1.12
Window {
id: main_window
visible: true
width: 1500
height: 1000
title: qsTr("Hello World")
Item {
width: main_window.width
height: main_window.height
LinearGradient {
anchors.fill: parent
start: Qt.point(0, 0)
end: Qt.point(main_window.width, 0)
gradient: Gradient {
GradientStop { position: 0.0; color: "#003cff" }
GradientStop { position: 1.0; color: "#9afff9" }
}
}
}
Rectangle {
id: sgfBox
anchors.fill: parent
color: "transparent"
Rectangle {
id: sfg
width: 175
height: 75
color: 'transparent'
RowLayout {
width: parent.width
height: parent.height
spacing: 25
Rectangle {
Layout.preferredWidth: 75
Layout.fillWidth: false
Layout.fillHeight: true
color: 'red'
}
Rectangle {
Layout.preferredWidth: 75
Layout.fillWidth: false
Layout.fillHeight: true
color: 'red'
}
}
MouseArea {
cursorShape: Qt.PointingHandCursor
anchors.fill: parent
drag {
target: sfg
}
}
}
}
Rectangle {
id: mask
anchors.fill: parent
color: "transparent"
Rectangle {
color: 'black'
x: 400
y: 200
width: 100
height: 100
opacity: 1
radius: 50
}
layer.enabled: true
layer.effect: OpacityMask {
maskSource: sgfBox
}
}
}
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
}
}
}
}
}
I am trying to create perceptive image from a normal image
I need something like this
from something like this
I tried different ways like rotate and use a mask like this
Image {
id: bug
source: "./Graphics/sample.png"
width: 200
height: 200
anchors.centerIn: parent
sourceSize: Qt.size(parent.width, parent.height)
smooth: true
transform: Rotation { origin.x: 30; origin.y: 30; axis { x: 0; y: 1; z: 0 } angle: 46 }
visible: true
layer.enabled: true
layer.effect: OpacityMask {
maskSource:
Image {
id: mask
source: "./mask.png"
sourceSize: Qt.size(parent.width, parent.height)
smooth: true
visible: false
}
}
}
Is there any proper way to actually create an effect like this.
I am not sure, if I got it right, but is it something like this, you want to achive?
Item {
width: 1000
height: 500
anchors.centerIn: parent
RectangularGlow {
id: effect
anchors.fill: img
glowRadius: 25
spread: 0.2
color: "black"
cornerRadius: 50
}
Image {
id: img
anchors.centerIn: parent
width: 1000
height: 500
source: 'source.png'
layer.enabled: true
layer.effect: OpacityMask {
maskSource: Rectangle {
width: 1000
height: 500
radius: 25
}
}
}
transform: Rotation { axis {x: 0.5; y: 1; z: 0} angle: 45 }
}
Or maybe it is a DropShadow you want to apply, instead of the RectangularGlow
DropShadow {
anchors.fill: img
horizontalOffset: -15
verticalOffset: 8
radius: 20
samples: 40
color: "#80000000"
source: Rectangle {
width: 1000
height: 500
radius: 25
}
}