Cursor shape changed even over an overlapping rectangle in QML - qt

With the following code, the green rectangle entirely overlaps the red rectangle, but when the mouse is over the (hidden) red rectangle, my cursor shape is still changed according to the red MouseArea cursorShape.
Any idea to prevent this behavior?
import QtQuick 2.0
Rectangle {
width: 360
height: 360
Rectangle {
color: "red"
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 100
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: "ClosedHandCursor"
}
}
Rectangle {
color: "green"
anchors.fill: parent
MouseArea {
anchors.fill: parent
hoverEnabled: true
}
}
}

Simply use 'containsMouse' property in the binding of cursorShape, and don't use the String form of enum values :
import QtQuick 2.0
Rectangle {
color: "white";
width: 400;
height: 400;
Rectangle {
color: "red";
anchors.top: parent.top;
anchors.left: parent.left;
width: 300;
height: 300;
MouseArea {
anchors.fill: parent;
hoverEnabled: true;
cursorShape: (containsMouse
? (pressed
? Qt.ClosedHandCursor
: Qt.OpenHandCursor)
: Qt.ArrowCursor);
}
}
Rectangle {
color: "green";
anchors.bottom: parent.bottom;
anchors.right: parent.right;
width: 300;
height: 300;
MouseArea {
anchors.fill: parent;
hoverEnabled: true;
}
}
}

import QtQuick 2.0
Rectangle {
width: 360
height: 360
Rectangle {
color: "red"
anchors.top: parent.top
anchors.bottom: parent.bottom
width: 100
MouseArea {
anchors.fill: parent
hoverEnabled: true
cursorShape: greenRectangle.hovered ? Qt.ArrowCursor : Qt.ClosedHandCursor;
}
}
Rectangle {
id: greenRectangle;
property bool hovered: false;
color: "green"
anchors.fill: parent
anchors.leftMargin: 20;
MouseArea {
anchors.fill: parent
hoverEnabled: true
onHoveredChanged: {
greenRectangle.hovered = !greenRectangle.hovered;
console.log(greenRectangle.hovered);
}
}
}
}

Related

Implementing a slider in QML with a VU-meter like image as a background

I am trying to create a slider that I can move up and down with my mouse. However, I want to use my own image as the background. I am currently trying to implement this with a OpacityMask. Basically, I am trying to make the opacity 0 from where the handle is to the right end of the slider.
I would ordinarily just move a rectangle that is same color as the background over it. However, I want whatever element is under the slider to be displayed when the slider is pulled back.
How can I create this behavior?
import QtQuick 2.7
import QtQuick.Templates 2.0 as T
import QtGraphicalEffects 1.12
import "."
T.Slider {
id: control
implicitWidth: 200
implicitHeight: 26
handle: Rectangle {
x: control.visualPosition * (control.width - width)
y: (control.height - height) / 2
width: 20
height: 15
radius: 5
color: control.pressed ? "#f0f0f0" : "#f6f6f6"
border.color: "gray"
}
background: OpacityMask {
anchors.fill: sliderImage
source: sliderImage
maskSource: mask
}
Image{
id: sliderImage
source: "./Jarvis2/images/volume_barH.png"
height: 20
width: parent.width
visible: false
}
Item{
id: mask
anchors.fill: sliderImage
Rectangle{
id: outer
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
width: control.visualPosition*parent.width
color: "gray"
opacity: 1
visible: false
}
Rectangle {
id: inner
color: "transparent"
z: 1
opacity: 1
anchors.left: outer.right
anchors.right: parent.right
anchors.top: outer.top
anchors.bottom: outer.bottom
visible: false
}
}
}
The slider at 100%:
The slider at around 70%:
The slider at around 24%
I think you can omit the OpacityMask and simply use a clipping Item:
Slider {
id: slider
width: 100
height: 300
orientation: Qt.Vertical
background: Item {
id: background
Item {
clip: true
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: (1 - slider.visualPosition) * slider.height
Rectangle { //Your image goes here
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: background.height
gradient: Gradient {
GradientStop { position: 0; color: "blue" }
GradientStop { position: 1; color: "red" }
}
}
}
}
}
You might have to fiddle a bit with the height of the clipping Item since there is some padding involved.
If you nevertheless want to use OpacityMask (because you want a different shape), you should put them together in the background:
Slider {
id: slider
width: 100
height: 300
orientation: Qt.Vertical
background: Item {
id: background
Rectangle { //Your image goes here
id: image
anchors.fill: parent
visible: false
gradient: Gradient {
GradientStop { position: 0; color: "blue" }
GradientStop { position: 1; color: "red" }
}
}
OpacityMask {
anchors.fill: parent
source: image
maskSource: mask
}
Item {
id: mask
visible: false
anchors.fill: parent
Rectangle {
radius: 10
anchors.left: parent.left
anchors.right: parent.right
anchors.bottom: parent.bottom
height: parent.height * slider.position
color: "white"
}
}
}
}

qt5/qml: how to implement advanced/addon/details switch? [duplicate]

I want to create an animated accordion-like element that expands on click. Here's how it should work.
When the user clicks one of the red rectangles, the green rectangle which is the actual content, should expand. I want this expansion to be animated. The height of the contents of the green rectangles could be different for each red header.
I have been able to implement the click-to-expand behavior, but there's no animation. Here is the code I currently have.
AccordionElement.qml
import QtQuick 2.5
import QtQuick.Layouts 1.1
ColumnLayout {
id: rootElement
property string title: ""
property bool isOpen: false
default property alias accordionContent: contentPlaceholder.data
anchors.left: parent.left; anchors.right: parent.right
// Header element
Rectangle {
id: accordionHeader
color: "red"
anchors.left: parent.left; anchors.right: parent.right
height: 50
MouseArea {
anchors.fill: parent
Text {
text: rootElement.title
anchors.centerIn: parent
}
cursorShape: Qt.PointingHandCursor
onClicked: {
rootElement.isOpen = !rootElement.isOpen
}
}
}
// This will get filled with the content
ColumnLayout {
id: contentPlaceholder
visible: rootElement.isOpen
anchors.left: parent.left; anchors.right: parent.right
}
}
And this is how it is used from the parent element:
Accordion.qml
ColumnLayout {
Layout.margins: 5
visible: true
AccordionElement {
title: "Title1"
accordionContent: Rectangle {
anchors.left: parent.left; anchors.right: parent.right
height: 20
color: "green"
}
}
AccordionElement {
title: "Title2"
accordionContent: Rectangle {
anchors.left: parent.left; anchors.right: parent.right
height: 50
color: "green"
}
}
AccordionElement {
title: "Title3"
accordionContent: Rectangle {
anchors.left: parent.left; anchors.right: parent.right
height: 30
color: "green"
}
}
// Vertical spacer to keep the rectangles in upper part of column
Item {
Layout.fillHeight: true
}
}
This produces the following result (when all rectangles are expanded):
Ideally I would like the green rectangles to roll out of the red rectangles (like paper out of a printer). But I am stuck on how to do this. I have tried several approaches using the height property, and I got the green rectangle to disappear but the white space remains under the red rectangle.
Any help would be appreciated. Is there an approach I'm missing?
Here is a quick and simple example:
// AccItem.qml
Column {
default property alias item: ld.sourceComponent
Rectangle {
width: 200
height: 50
color: "red"
MouseArea {
anchors.fill: parent
onClicked: info.show = !info.show
}
}
Rectangle {
id: info
width: 200
height: show ? ld.height : 0
property bool show : false
color: "green"
clip: true
Loader {
id: ld
y: info.height - height
anchors.horizontalCenter: info.horizontalCenter
}
Behavior on height {
NumberAnimation { duration: 200; easing.type: Easing.InOutQuad }
}
}
}
// Acc.qml
Column {
spacing: 5
AccItem {
Rectangle {
width: 50
height: 50
radius: 50
color: "blue"
anchors.centerIn: parent
}
}
AccItem {
Rectangle {
width: 100
height: 100
radius: 50
color: "yellow"
anchors.centerIn: parent
}
}
AccItem {
Rectangle {
width: 75
height: 75
radius: 50
color: "cyan"
anchors.centerIn: parent
}
}
}
You are needlessly over-complicating it with the anchors and the layouts. It doesn't seem the problem calls for any of those.
Update: I slightly refined the implementation, compared to the initial one the content would actually slide out of the header as paper out of printer rather than simply being unveiled, and also removed the source of a false positive binding loop warning.

GridLayout: width and height issues

I have a few questions about GridLayout in QtQuickLayouts 1.3:
How should I make it , so the GridLayout places into CORRECT row/column every element of my grid even if the size of the element is not clearly specified by with or height parameter?
Let me remove the width and height and I will show you the broken layout. I will just comment it out:
Item {
id: test_item
//Layout.fillWidth: true
//height: 20
}
Full source code of the .qml file is here, and can be tested with bin/qmlscene:
import QtQuick 2.7
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.3
ApplicationWindow {
width: 400
height: 500;
ColumnLayout {
anchors.fill: parent
GridLayout {
anchors.fill: parent
columns: 2
Label {
text:"Email:"
}
Rectangle {
width: 80; height: 20
border.color: "magenta"
}
Label {
text: "Full Name:"
Layout.fillWidth: true
}
Item {
id: test_item // the commented out portion, to show the flaw
//Layout.fillWidth: true
//height: 20
}
Label {
text: "Gender:"
}
RowLayout {
Layout.minimumHeight: 20
Layout.fillWidth: true
RadioButton {
text: "Male"
width: parent.width/2
height: 20
}
RadioButton {
text: "Female"
width: parent.width/2
height: 20
}
}
Label {
text: "Mobile phone:"
}
Rectangle {
width: 80; height: 20
border.color: "magenta"
}
}
Row {
Button {
text: "Cancel"
}
Button {
text: " Ok "
}
}
}
}
The 'broken` output looks like this:
While the correct output , with Item's size specified looks like this:
2) The second question. How do I load a component into a GridLayout cell via Loader using Component type? For example, this is my full source with the Component item and the component is missing when rendering:
import QtQuick 2.7
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.3
ApplicationWindow {
width: 400
height: 500;
ColumnLayout {
anchors.fill: parent
GridLayout {
anchors.fill: parent
columns: 2
Label {
text:"Email:"
}
Rectangle {
width: 80; height: 20
border.color: "magenta"
}
Label {
text: "Full Name:"
Layout.fillWidth: true
}
Loader {
id: test_item
sourceComponent: field_template
}
Label {
text: "Gender:"
}
RowLayout {
Layout.minimumHeight: 20
Layout.fillWidth: true
RadioButton {
text: "Male"
width: parent.width/2
height: 20
}
RadioButton {
text: "Female"
width: parent.width/2
height: 20
}
}
Label {
text: "Mobile phone:"
}
Rectangle {
width: 80; height: 20
border.color: "magenta"
}
}
Row {
Button {
text: "Cancel"
}
Button {
text: " Ok "
}
}
}
Component {
id: field_template
Item {
Layout.fillWidth: true
height: 33
Rectangle {
border.color: "blue"
color: "transparent"
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.rightMargin: 10
TextEdit {
anchors.fill: parent
anchors.leftMargin: 5
anchors.topMargin: 3
anchors.rightMargin: 2
clip: true
text: "type here"
}
}
}
}
}
The picture of the output rendered by qmlscene is this:
I have correctly speecified witdht and height, why isn't the component being loaded with Loader ?
For the second question folibis is right in the comment. You just have to check the size. Here, is a working code.
...
Item {
Layout.fillWidth: true
//width: 80
height:20
Loader {
id: test_item
anchors.fill: parent
sourceComponent: field_template
}
}
...
Component {
id: field_template
Item {
Rectangle {
border.color: "blue"
color: "transparent"
anchors.left: parent.left
anchors.right: parent.right
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.rightMargin: 10
TextEdit {
anchors.fill: parent
anchors.leftMargin: 5
anchors.topMargin: 3
anchors.rightMargin: 2
clip: true
text: "type here"
}
}
}

Scrollist issue in QML

I'm trying to make scrollable list in QML.
Though its running successfully but whenever am varying the size of main window the pattern of the list distorts or the items overlaps on each other.
Any suggestions where is the bug in my code.
Tried to vary the anchors but then also no luck on the issue.
Below is the code snippet
import QtQuick 1.1
Item{
....
Rectangle{
....
Rectangle {
....
color: "white"
anchors.centerIn: main.Center
Rectangle {
...
ListView {
id: list_min
....
snapMode: ListView.SnapToItem
model: 20
delegate: Rectangle{
width: list_min.width
height: list_min.height
color: "transparent"
Text {
anchors.verticalCenter: parent.verticalCenter
text: index+1
font.pixelSize: parent.width/1.5
}
Text {
text: index+2
font.pixelSize: parent.width/1.5
anchors.top: parent.top
anchors.topMargin: 150
}
Text {
text: index
font.pixelSize: parent.width/1.5
anchors.bottom: parent.bottom
anchors.bottomMargin: 150
}
}
onMovementEnded: list_min.currentIndex = list_min.visibleArea.yPosition * list_min.count
Component.onCompleted: list_min.visibleArea
}
Rectangle {
....
gradient: Gradient {
GradientStop { position: 0.0; color: "black" }
....
GradientStop { position: 1.0; color: "black" }
}
}
}
}
I would recommend using the Column tag to place the text elements in the delegate.
Also for overlay_min, you need to either set the height & width OR the anchors.fill, not both.
I have modified the source code as below:
import QtQuick 1.1
Item{
width: 300
height: 240
Rectangle{
id:main
width: parent.width
height: parent.height
Rectangle {
id :frame_min
width: 120
height: main.height
color: "white"
anchors.centerIn: main.Center
Rectangle {
id: mSpinner
anchors.centerIn: parent
width: frame_min.width - 10
height: frame_min.height
color: "white"
border.color: "black"
border.width: 5
ListView {
id: list_min
width: mSpinner.width
height: mSpinner.height
anchors.topMargin: 0
anchors.top: parent.top
clip: true
snapMode: ListView.SnapToItem
model: 20
delegate: Rectangle{
width: list_min.width
height: list_min.height
color: "transparent"
Column{
anchors.verticalCenter: parent.verticalCenter
Text {
//anchors.verticalCenter: parent.verticalCenter
text: index+1
font.pixelSize: list_min.width/1.5
}
Text {
text: index+2
font.pixelSize: list_min.width/1.5
//anchors.top: parent.top
//anchors.topMargin: 150
}
Text {
text: index
font.pixelSize: list_min.width/1.5
//anchors.bottom: parent.bottom
//anchors.bottomMargin: 150
}
}
}
onMovementEnded: list_min.currentIndex = list_min.visibleArea.yPosition * list_min.count
Component.onCompleted: list_min.visibleArea
}
Rectangle {
id: overlay_min
width: frame_min.width
height: frame_min.height
//anchors.fill: frame_min
gradient: Gradient {
GradientStop { position: 0.0; color: "black" }
GradientStop { position: 0.34; color: "transparent" }
GradientStop { position: 0.35; color: "white" }
GradientStop { position: 0.66; color: "transparent" }
GradientStop { position: 1.0; color: "black" }
}
}
}
}
}
}

QML : Drop-down menu that opens upward

I need to have drop-down that opens upwards on clicking on Menu button in QML.
I have tried to use the listview for the same, but in the implementation we are getting drop-down which opens downwards.
Any suggestions with reference to below snippet.
import QtQuick 1.1
Rectangle {
width: 800
height: 480
Rectangle {
id:comboBox
property variant items: ["Red", "Blue", "Green"]
signal comboClicked;
x: 651
y: 344
width: 141
height: 30;
z: 0
smooth:true;
Rectangle {
id:chosenItem
radius:4;
width:parent.width;
height:comboBox.height;
color: "#454b4d"
smooth:true;
Text {
anchors.top: parent.top;
anchors.margins: 8;
id:chosenItemText
x: 11
y: 5
color: "#ffffff"
text:"Menu";
anchors.topMargin: 5
anchors.left: parent.left
anchors.leftMargin: 12
font.family: "Arial"
font.pointSize: 14;
smooth:true
}
MouseArea {
width: 400
height: 30
anchors.bottomMargin: 0
anchors.fill: parent;
onClicked: {
comboBox.state = comboBox.state==="dropDown"?"":"dropDown"
}
}
}
Rectangle {
id:dropDown
width:comboBox.width;
height:0;
clip:true;
radius:4;
anchors.top: chosenItem.bottom;
anchors.margins: 2;
color: "lightblue"
ListView {
id:listView
height:500;
model: comboBox.items
currentIndex: 0
delegate: Item{
width:comboBox.width;
height: comboBox.height;
Text {
text: modelData
anchors.top: parent.top;
anchors.left: parent.left;
anchors.margins: 5;
}
MouseArea {
anchors.fill: parent;
onClicked: {
comboBox.state = ""
chosenItemText.text = modelData;
listView.currentIndex = index;
}
}
}
}
}
states: State {
name: "dropDown";
PropertyChanges { target: dropDown; height:30*comboBox.items.length }
}
transitions: Transition {
NumberAnimation { target: dropDown; properties: "height"; easing.type: Easing.OutExpo; duration: 1000 }
}
}
}
Try to change the anchors of the dropDown item:
that
anchors.top: chosenItem.bottom;
should become
anchors.bottom: chosenItem.top;

Resources