you can find my code example below. When I try to add "progress" qml says thatinvalid property name "progress". (M16) How can I fix this problem
ProgressBar {
x:300
y: 200
value: 0.5
background: Rectangle {
radius: 10
color: "red"
border.color: "gray"
border.width: 1
implicitWidth: 200
implicitHeight: 10
}
progress: Rectangle{
}
}
Assuming you'd like to customize the progress indicator with in the ProgressBar: use the contentItem property. See the documentation for more information.
Related
I'm using the customized Checkbox example that Qt posted with QtQuick 2.15 with Qt 6.2.1:
CheckBox {
id: control
text: qsTr("CheckBox")
checked: true
indicator: Rectangle {
implicitWidth: 26
implicitHeight: 26
x: control.leftPadding
y: parent.height / 2 - height / 2
radius: 3
border.color: control.down ? "#17a81a" : "#21be2b"
Rectangle {
width: 14
height: 14
x: 6
y: 6
radius: 2
color: control.down ? "#17a81a" : "#21be2b"
visible: control.checked
}
}
contentItem: Text {
text: control.text
font: control.font
opacity: enabled ? 1.0 : 0.3
color: control.down ? "#17a81a" : "#21be2b"
verticalAlignment: Text.AlignVCenter
leftPadding: control.indicator.width + control.spacing
}
}
Using that control as is has some weird effects. When the control is hovered, the old checkobx box shows up as well as the old indicator when clicked.
// Checked
// Checked & Hovered
// Unchecked & Hovered
// No mouse interaction
This is weird, I'm not able to pinpoint the issue here.
I just tried the code you posted. Works (incorrectly) as you say in Qt 6.2.2; works right in Qt 5.15.2. I'd be inclined to submit an issue on it.
It works fine if you set hoverEnabled:false. It is by default set to true in 6.x, what was probably not the case in 5.x.
Found the same issue here. I solved it by using the QuickControls CheckDelegate as a base. Not ideal, but works.
I've seen that with the following code:
Window {
width: 440
height: 280
visible: true
ComboBox {
id: control
model: ["First", "Second", "Third"]
anchors.bottom: parent.bottom
anchors.bottomMargin: 10
delegate: ItemDelegate {
width: control.width
contentItem: Text {
text: modelData
color: "#21be2b"
font: control.font
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
highlighted: control.highlightedIndex === index
}
indicator: Canvas {
id: canvas
x: control.width - width - control.rightPadding
y: control.topPadding + (control.availableHeight - height) / 2
width: 12
height: 8
contextType: "2d"
Connections {
target: control
function onPressedChanged() { canvas.requestPaint(); }
}
onPaint: {
context.reset();
context.moveTo(0, 0);
context.lineTo(width, 0);
context.lineTo(width / 2, height);
context.closePath();
context.fillStyle = control.pressed ? "#17a81a" : "#21be2b";
context.fill();
}
}
contentItem: Text {
leftPadding: 0
rightPadding: control.indicator.width + control.spacing
text: control.displayText
font: control.font
color: control.pressed ? "#17a81a" : "#21be2b"
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
background: Rectangle {
implicitWidth: 120
implicitHeight: 40
border.color: control.pressed ? "#17a81a" : "#21be2b"
border.width: control.visualFocus ? 2 : 1
radius: 2
}
popup: Popup {
y: control.height - 1
width: control.width
implicitHeight: contentItem.implicitHeight
padding: 1
contentItem: ListView {
clip: true
implicitHeight: contentHeight
model: control.popup.visible ? control.delegateModel : null
currentIndex: control.highlightedIndex
ScrollIndicator.vertical: ScrollIndicator { }
}
background: Rectangle {
border.color: "#21be2b"
radius: 2
}
}
}
}
(The ComboBox example from Qt documentation, at the bottom of the window)
If you click on the ComboBox, the popup its shown above the control (because its out of space below). I would like to know which signal or variable makes this automatic behaviour, so that i can capture it and trigger a different action.
I'm not sure I fully understand the question, but hopefully this answers it.
The code within popup uses a ternary to navigate the popup visibility. See this post regarding QML conditional bindings (ternary operators)
model: control.popup.visible ? control.delegateModel : null
"If popup visible, set model equal to delegate model. Else set popup model null"
Lets talk about signals and slots. If you want to easily view all of the signal/slots on a qml object type go within the block and type 'on'. Then view all of the code fillins from there. You can check the QT documentation as well.
If I were to implement this, I may have done it differently using the popup signals: open(), close(). It will add more lines of code, but improve readability and utilize the signal/slot mechanism. The current method creates very tight coupling between QML components.
Hey, thanks for your answer! Basically what I need to do is work with
popup y-coordinate. More specifically evaluate a condition to assign
the y property of popup, depending on how much space is left to open
it below the control... like this: popup.y = some_condition?
control.height - 1 : popup.implicitHeight + 1 QML already has some way
to know if the space is enough... and then readjust the popup
y-coordinate. I would like to know which inner-mechanism handles this.
Three ways to tackle it come to mind:
Use Layouts
Use Component attributes/member data
Use anchors
Layouts
Wrap all of your components inside of a column layout. Have your column layout fill up the space of both components combined. Then you can set minimum, preferred, and maximum width/heights of each component. In addition, you could set the preferred size for one component. Then call Layout.fill width/column to have it automatically take up the rest of the space.
Component attributes/member data
Mathmatically calculate the .y data using all of your other components.
popup.y = appWindow.y - componentWindow.y
or
popup.y = doMath(some property var of component X)
Anchors
Anchor your popup component to another component. So suppose you wanted a popup underneath some rectangle component.
Anchors.top = myRect.bottom
I'm a huge fan of using nested layouts to create dnyamic screens that always fill up spaces in the way I expect them to. It prevents tightly coupled components and lets Qt do the hard work.
I wanted to have the Material style ProgressBar component, but with some modifications to make it's height adjustable.
So far so good, I had the result I wanted.
So I just copied this code inside MyPb.qml to use it as a component:
import QtQuick 2.11
import QtQuick.Templates 2.4 as T
import QtQuick.Controls.Material 2.4
import QtQuick.Controls.Material.impl 2.4
T.ProgressBar {
id: control
property real radius: 3
contentItem: ProgressBarImpl {
implicitHeight: control.height
scale: control.mirrored ? -1 : 1
color: control.Material.accentColor
progress: control.position
indeterminate: control.visible && control.indeterminate
}
background: Rectangle {
implicitWidth: control.width
implicitHeight: control.height
radius: control.radius
color: Qt.rgba(control.Material.accentColor.r, control.Material.accentColor.g, control.Material.accentColor.b, 0.25)
}
}
Which gives this result for the sake of example:
With the code:
Rectangle {
width: 600
height: 300
color: "black"
MyPb {
anchors.centerIn: parent
id: prg
width: 100
height: 20
indeterminate: false
radius: 5
visible: true
value: 0.5
}
}
Because ProgressBarImpl doesn't really support radius, the rounded corners are "buried" under the opaque progress rectangle as can be seen on the picture (left of progress bar).
Now, the reason I'm not making my own progress bar is that I want the "indeterminate" animation as well. So I thought it would be much
simpler to reuse the Qt implementation than starting making my own
animations.
So I wonder if there would be a way to have the Material progress bar, but apply to it some kind of treatment to get rounded corners both with indeterminate = false/true.
Any help would be appreciated!
See the following post in the Qt forum:
https://forum.qt.io/topic/91649/make-a-round-progress-bar/7
The progress bar proposed there consists of the following components:
a rounded Rectangle for the "trough" of the progress bar
an Item that acts as a rectangular clip path
a rounded Rectangle inside that Item, used as the coloured bar
Adapted to your question, I get the following code as a proof-of-concept:
import QtQuick 2.9
Rectangle {
property int percentage: 40
id: root
width: 400
height: 100
radius: height / 2
color: "#333"
Item {
id: cliprect
anchors.bottom: parent.bottom
anchors.top: parent.top
anchors.left: parent.left
width: parent.width * parent.percentage / 100
clip: true
Rectangle {
width: root.width
height: root.height
radius: height / 2
anchors.bottom: parent.bottom
anchors.left: parent.left
color: "#e33"
}
}
}
It should be easy to move that into a template / make it compatible with the Material properties.
You could try setting an OpacityMask on the contentItem using the background item as a mask source.
If that doesn't work out, it will be easier just to create a progress bar. It is a very trivial and non-interactive component with a tiny usage interface after all.
Now, while porting my app to Qt 5.9 I've faced some strange behavior. The code describing the issue is below:
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
Window {
visible: true
width: 600
height: 800
title: qsTr("Test")
Row {
id: base
property var arr: []
property color currentColor: "red"
anchors.centerIn: parent
spacing: 5
Repeater {
model: 10
delegate: Rectangle {
width: 50
height: 50
border.width: 1
border.color: "grey"
color: base.arr[index] === undefined ? "white" : base.arr[index]
MouseArea {
anchors.fill: parent
onClicked: {
base.currentColor = Qt.rgba(Math.random(),Math.random(),Math.random(),1);
base.arr[index] = base.currentColor;
base.arr = base.arr; // trick to fire changing event
console.log(base.arr)
}
}
}
}
}
}
So there is array of rectangles and while pressing one of them I get random color and place it in the array base.arr at some index as item one. There is a property base.currentColor to keep the current color. But the problem is that if I assign new color to an item all previous items change color too.
I guess the problem is in line
base.arr[index] = base.currentColor;
It looks that this line creates some unexpected binding or reference or whatever I don't see. As I know the only way to create binding in Js is Qt.binding but here I don't use that.
The workaround to break this behavior is something like this:
base.arr[index] = Qt.rgba(base.currentColor.r, base.currentColor.g, base.currentColor.b, base.currentColor.a);
but it looks overhead and dirty solution.
I would be glad if someone can explain this strange behavior.
QML color is actually a color object.
In JavaScript objects are copied by reference, so a QML color variable actually behaves more like a pointer.
On this line:
base.arr[index] = base.currentColor;
the array element is set as a reference to the currentColor object.
When each array element is set, it gets set as a reference to the same currentColor object! Thus changing the currentColor changes every element in the array.
Instead of this:
property color currentColor: "red"
use this:
property string currentColor: "red"
strings in QML are always copied by value, so you will no longer have a problem.
Full code:
import QtQuick 2.9
import QtQuick.Window 2.2
import QtQuick.Controls 2.2
Window {
visible: true
width: 600
height: 800
title: qsTr("Test")
Row {
id: base
property var arr: []
property string currentColor: "red"
anchors.centerIn: parent
spacing: 5
Repeater {
model: 10
delegate: Rectangle {
width: 50
height: 50
border.width: 1
border.color: "grey"
color: base.arr[index] === undefined ? "white" : base.arr[index]
MouseArea {
anchors.fill: parent
onClicked: {
base.currentColor = Qt.rgba(Math.random(),Math.random(),Math.random(),1);
base.arr[index] = base.currentColor;
base.arr = base.arr; // trick to fire changing event
console.log(base.arr)
}
}
}
}
}
}
What I can't understand is -
you said you are porting your app to Qt 5.9... If you are porting from a previous version of Qt, then I am surprised that the code did not behave the same way in the previous version.
import QtQuick 2.4
import QtQuick.Window 2.2
Window
{
visible: true
height: 500
width: 500
property VisualItemModel contentToBeShownOnTabClick : visualItemModelDemo
property variant tabLabels : ["Navigation", "Payload", "System Control"]
VisualItemModel
{
id: visualItemModelDemo
Rectangle
{
id: navigationTab
color: "green"
height: 200
width: 200
}
Rectangle
{
id: navigationTab1
color: "darkgreen"
height: 200
width: 200
}
Rectangle
{
id: navigationTab2
color: "lightgreen"
height: 200
width: 200
}
}
MainForm
{
Component
{
id: tabsOnBottomComponent
Repeater
{
model: tabLabels
// The Tabs
Rectangle
{
id: tabsOnBottom
// This anchoring places the tabs on the outer top of the parent rectangle.
anchors.top: parent.bottom
anchors.topMargin: 180
color: "lightsteelblue"
border.color: "steelblue"
border.width: 2
implicitWidth: Math.max ((labelTabsBottom.width + 4), 80)
implicitHeight: 20
radius: 2
// Tabs Text/Label
Text
{
id: labelTabsBottom
anchors.centerIn: parent
color: "white"
rotation: 0
// With reference to mode: tabLabels
text: modelData
font.pointSize: 11
}
MouseArea
{
anchors.fill: parent
onClicked: bottomTabClicked (index);
}
}
}
}
Rectangle
{
// The things which get displayed on clicking of a tab will be shown in this rectangle.
id: areaForTabContents
border.color: "black"
border.width: 10
height: parent.height
width : parent.width
color : "pink"
// These are the tabs displayed in one row - horizontally.
Row
{
id: horizontalTabs
Loader
{
anchors.fill: parent
sourceComponent: tabsOnBottomComponent
}
}
}
anchors.fill: parent
}
}
This gets shown as follows:
whereas I want it to see 3 rectangles there side by side.
Loader is not a transparent type w.r.t. the containing type, Row in this case. I think this is an issue related to creation context and the way Repeater works. From the documentation of the latter:
Items instantiated by the Repeater are inserted, in order, as children of the Repeater's parent. The insertion starts immediately after the Repeater's position in its parent stacking list. This allows a Repeater to be used inside a layout.
The Rectangles are indeed added to the parent which is the Loader, they stack up - Loader does not provide a positioning policy - then they are added to the Row resulting in just one Item (the last one) to be visible.
You can tackle the problem with few different approaches, depending on the properties you want to maintain or not. I would get rid of anchoring in the Component and move it to the containing Row. A too specific anchoring inside a Component could be a pain in the neck when it is instanced and used all over a (not so small) project.
As a first approach you can re-parent the Repeater to the Row, i.e. you can rewrite code as:
Row
{
id: horizontalTabs
Loader
{
sourceComponent: tabsOnBottomComponent
onLoaded: item.parent = horizontalTabs
}
}
However this would result in warnings due to the Component anchoring references not working as expected any more.
If you still want to maintain the anchoring, as defined in the Component, and off-load the creation, you can go for the dynamic way (if the semantics fits in your use case), i.e. you can use createObject. This way you totally avoid the Loader and the related issue. For instance, you can create the Repeater once the Row has completed its creation:
Row
{
id: horizontalTabs
Component.onCompleted: tabsOnBottomComponent.createObject(horizontalTabs)
}
Clearly, the creation code can be move anywhere else, depending on your needs.