How to change ScrollBar color in QML? - qt

I've tried to customize ScrollBar using contentItem but the ScrollBar doesn't display in this case. Are there any other ways to change ScrollBar color?
ListView {
anchors.fill : parent
ScrollBar.vertical : ScrollBar {
anchors.rightMargin: 10 * AppTheme.scaleValue
contentItem: Rectangle {
color: "red"
}
}
boundsBehavior : Flickable.StopAtBounds
currentIndex : 0
focus : true
clip : true
model : checkDataModel
delegate: Rectangle {
id : rect
width : onlineChecksUpperPanel.width - 15 * AppTheme.scaleValue
height : 40 * AppTheme.scaleValue
color : index % 2 == 0 ? "#ECEEF1" : "#FFFFFF"
Text {
text : checkNum
font.family : AppTheme.fontBold.name
font.pixelSize : AppTheme.textSizePxSmaller
textFormat : Text.StyledText
color : AppTheme.textColorTouchDark
anchors.verticalCenter: parent.verticalCenter
leftPadding: 16 * AppTheme.scaleValue
}
}
}

What you're missing is an implicitWidth on the contentItem. It needs to know what size to draw the scrollbar. It will work fine like this:
ScrollBar.vertical : ScrollBar {
anchors.rightMargin: 10 * AppTheme.scaleValue
contentItem: Rectangle {
implicitWidth: 6
color: "red"
}
}

The below code is ok for me. maybe a variable does not exist in your source code and the viewer can not render the item.
import QtQuick 2.12
import QtQuick.Controls 2.12
ListView {
anchors.fill : parent
ScrollBar.vertical : ScrollBar {
anchors.rightMargin: 10 * AppTheme.scaleValue
contentItem: Rectangle {
color: "red"
}
}
boundsBehavior : Flickable.StopAtBounds
currentIndex : 0
focus : true
clip : true
model : 20
delegate: Rectangle {
id : rect
width : parent.width
height : 50
color : index % 2 == 0 ? "#ECEEF1" : "#FFFFFF"
Text {
text : index
textFormat : Text.StyledText
color : "red"
anchors.fill: parent
}
}
}

Related

Doesn't see popup menu on combobox

I'm trying to set a new style to comboBox in qml and get in trouble my combobox doesn't want to show me drop-down list everything else is fine, here is code
The code I took from Internet
T.ComboBox {
id: _comboBox
anchors.bottom: _borderedTextboxPoints.top
anchors.horizontalCenter: _borderedTextboxPoints.horizontalCenter
anchors.bottomMargin: 10
delegate: T.ItemDelegate { //! Changing style of items in list
width: _comboBox.width
contentItem: Text {
text: modelData
color: "black"
font: _comboBox.font
elide: Text.ElideRight
verticalAlignment: Text.AlignVCenter
}
highlighted: _comboBox.highlightedIndex === index
}
indicator: Canvas { //! Changing style of indicator
id: canvas
x: _comboBox.width - width - _comboBox.rightPadding - 5
y: _comboBox.topPadding + (_comboBox.availableHeight - height) / 2
width: 12
height: 8
contextType: "2d"
Connections { //! Changing style on pressed
target: _comboBox
function onPressedChanged() { canvas.requestPaint(); }
}
onPaint: {
context.reset();
context.moveTo(0, 0);
context.lineTo(width, 0);
context.lineTo(width / 2, height);
context.closePath();
context.fillStyle = _comboBox.pressed ? "#722ed1" : "#531dab";
context.fill();
}
}
contentItem: Text {
leftPadding: 5
rightPadding: _comboBox.indicator.width + _comboBox.spacing
text: _comboBox.displayText
font: _comboBox.font
color: "black"
verticalAlignment: Text.AlignVCenter
elide: Text.ElideRight
}
background: Rectangle {
implicitWidth: 120
implicitHeight: 40
border.color: _comboBox.pressed ? "#2f54eb" : "#1d39c4"
border.width: _comboBox.visualFocus ? 2 : 1
radius: 10
}
popup: T.Popup { //! Changing style of drop-down list
y: _comboBox.height - 1
width: _comboBox.width
implicitHeight: contentItem.implicitHeight
padding: 1
contentItem: ListView {
clip: true
implicitHeight: contentHeight
model:_comboBox.popup.visible ? _comboBox.delegateModel : null
currentIndex: _comboBox.highlightedIndex
T.ScrollIndicator.vertical: T.ScrollIndicator { }
}
}
}
That's look like this
In the popup code add a z and use an index higher than 1
popup: T.Popup { //! Changing style of drop-down list
...
padding: 1
z: 4
...
I used 4 as the z, here because I knew 4 will definitely work. But maybe 2 too would have worked.
This usually happens when you are showing the combo box in a popup.

Calculate TableView height according to Image in Delegate

I have a TableView with the following output:
Item {
property string picture
//...
id: root
Rectangle {
id: rect
anchors.fill: parent
border.width: 1
border.color: "black"
}
Image {
id: image
anchors.centerIn: parent
source: root.picture.length > 0 ? "data:image/png;base64," + root.picture : ""
fillMode: Image.PreserveAspectFit
sourceSize.width: rect.width - rect.border.width * 2
sourceSize.height: rect.height - rect.border.height * 2
}
//...
}
So I would have expected the Image fits in the Rectangle but it does not.
The TableView looks like this:
Item {
id: root
//...
HorizontalHeaderView {
id: horizontalHeaderView
syncView: tableView
anchors.left: tableView.left
model: [qsTr("Id"), qsTr("Question"), qsTr("Answer 1"), qsTr(
"Answer 2"), qsTr("Answer 3"), qsTr("Answer 4"), qsTr(
"Correct Answer"), qsTr("Picture")]
}
TableView {
id: tableView
width: parent.width
height: parent.height - horizontalHeaderView.height
anchors.top: horizontalHeaderView.bottom
boundsBehavior: Flickable.StopAtBounds
reuseItems: true
clip: true
property var columnWidths: [60, 220, 220, 220, 220, 220, 100, 140]
columnWidthProvider: function (column) {
return columnWidths[column]
}
model: questionsProxyModel
delegate: DelegateChooser {
id: chooser
//... More DelegateChoices here for the other columns but not
//.. interesting for the issue here
DelegateChoice {
column: 7
delegate: PictureDelegate {
id: pictureDelegate
width: tableView.columnWidthProvider(column)
picture: model.picture
}
}
}
ScrollBar.vertical: ScrollBar {}
}
}
So in the TableView I provide the width to each delegate via columnWidthProvider which works fine.
The height is calculated automatically according to the content of the childs. This for example makes sure all the text always fits:
Now how can I take the heigth the Image in the delegate needs to proper scale into account?
The Issue could be fixed by making the Rectangle the root of Image and using anchors.fill instead of anchors.centerIn
Rectangle {
property string picture
//...
color: "transparent"
border.width: 1
border.color: "black"
id: root
Image {
id: image
anchors.fill: parent
anchors.margins: root.border.width
source: root.picture.length > 0 ? "data:image/png;base64," + root.picture : ""
fillMode: Image.PreserveAspectFit
}
//...
}

QML - GridLayout - unable to center a page using it

I'm new to Qt and QML and while I'm trying to learn them I've encountered the following problem which I'm not sure why they appeared.
I'm having a button, at the moment when I'm pressing it will display a new purple Rectangle over the screen. I am trying to position it at the center of the screen, or in other words to fill the whole screen, but for some reason, I can't do that, and It's always going to start from the beginning of Item 2 instead of the beginning of the screen. Also, it's going to be placed under Item 1 and Item 3 instead to overlay them.
MY CODE:
import QtQuick 2.14
import QtQuick.Window 2.14
import QtQuick.Layouts 1.14
import QtQuick.Controls 2.12
Window {
id: mainD
visible: true
width: 640
height: 480
title: qsTr("Hello World")
GridLayout {
id : grid
anchors.fill: parent
rows : 12
columns : 20
property double colMulti : grid.width / grid.columns
property double rowMulti : grid.height / grid.rows
function prefWidth(item){
return colMulti * item.Layout.columnSpan
}
function prefHeight(item){
return rowMulti * item.Layout.rowSpan
}
Rectangle {
id: id1
color : 'red'
Layout.column: 0
Layout.rowSpan: 10
Layout.columnSpan: 2
Layout.preferredWidth : grid.prefWidth(this)
Layout.preferredHeight : grid.prefHeight(this)
}
Rectangle {
id: id2
color : 'green'
Layout.column: 2
Layout.rowSpan: 10
Layout.columnSpan: 18
Layout.preferredWidth : grid.prefWidth(this)
Layout.preferredHeight : grid.prefHeight(this)
Button{
width: 100
height: 100
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
onClicked: {
id2.state = "STATE_1"
}
}
StackView{
id: st
width: parent.width
height: parent.height + 100
anchors.horizontalCenter: grid.parent.horizontalCenter
anchors.verticalCenter: grid.parent.verticalCenter
visible: false
Rectangle{
anchors.fill: parent
color: "purple"
opacity: 0.7
Button{
width: 100
height: 100
onClicked: {
id2.state = "STATE_2"
}
}
}
}
states: [
State{
name: "STATE_1"
PropertyChanges {
target: st;
visible: true
}
},
State{
name: "STATE_2"
PropertyChanges {
target: st;
visible: false
}
}
]
}
Rectangle {
id: id3
color : 'blue'
Layout.column: 18
Layout.rowSpan: 10
Layout.columnSpan: 2
Layout.preferredWidth : grid.prefWidth(this)
Layout.preferredHeight : grid.prefHeight(this)
}
}
}
Can anyone explain to me what I am doing wrong?
Purple rectangle is an initial item of StackView object with an id "st". It is hidden initially.
"id2" is a visual parent of "st". Coordinates of "st" are relative to its visual parent. You are setting its width to be its parent's width and height to be parent's height + 100 so its (0,0) coordinate goes to parent's (0,0). You should read more from the documentation: Visual Parent in Qt Quick.
If you want to fill the whole screen with purple rectangle and position it on top of other visual items you can do it by moving "st" out from the "grid" and place it on the same level with it. Now both "grid" and "st" are children of "mainD", and because StackView is below "grid" you don't need to play with z values but when "st" becomes visible it is rendered on top of "grid".
Window {
id: mainD
...
GridLayout {
id : grid
...
}
StackView{
id: st
width: parent.width
height: parent.height// + 100
//anchors.horizontalCenter: grid.parent.horizontalCenter
//anchors.verticalCenter: grid.parent.verticalCenter
visible: false
Rectangle{
anchors.fill: parent
color: "purple"
opacity: 0.7
Button{
width: 100
height: 100
onClicked: {
id2.state = "STATE_2"
}
}
}
}
}
I recommend Positioning elements chapter from free Qt5 Cadaques book for further reading.
I'm having a button, at the moment when I'm pressing it will display a new purple Rectangle over the screen. I am trying to position it at the center of the screen, or in other words to fill the whole screen
As #talamaki mentioned if you want the purple to fill the whole background it is better to have it as child of the main Item instead of having it be part of the grid, and then have it extend the allocated space inside the grid.
but for some reason, I can't do that, and It's always going to start
from the beginning of Item 2 instead of the beginning of the screen.
That is because of how grids work. Think of it as like a chess board, item 1 already occupies the first two columns so item 2 will start from 3rd column, and any child of item 2 stars from the coordinate system of item 2. You could make it extend beyond it's starting point but I think it would be cleaner to have the background on the root item.
Also, it's going to be placed under Item 1 and Item 3 instead to
overlay them.
To have the purple be underneath 1 and 3 it has to be drawn first (should come first in the QML). If you don't want the button to be affected you should put it below the GridLayout in the QML file so that it is drawn last over it. Putting all this together would be something like this:
import QtQuick 2.14
import QtQuick.Window 2.14
import QtQuick.Layouts 1.14
import QtQuick.Controls 2.12
Window {
id: mainD
visible: true
width: 640
height: 480
title: qsTr("Hello World")
Rectangle{
id: background
anchors.fill: parent
color: "purple"
opacity: 0.7
visible: false
}
GridLayout {
id : grid
anchors.fill: parent
rows : 12
columns : 20
property double colMulti : grid.width / grid.columns
property double rowMulti : grid.height / grid.rows
function prefWidth(item){
return colMulti * item.Layout.columnSpan
}
function prefHeight(item){
return rowMulti * item.Layout.rowSpan
}
Rectangle {
id: id1
color : 'red'
Layout.column: 0
Layout.rowSpan: 10
Layout.columnSpan: 2
Layout.preferredWidth : grid.prefWidth(this)
Layout.preferredHeight : grid.prefHeight(this)
}
Rectangle {
id: id2
color : 'green'
Layout.column: 2
Layout.rowSpan: 10
Layout.columnSpan: 16
Layout.preferredWidth : grid.prefWidth(this)
Layout.preferredHeight : grid.prefHeight(this)
}
Rectangle {
id: id3
color : 'blue'
Layout.column: 18
Layout.rowSpan: 10
Layout.columnSpan: 2
Layout.preferredWidth : grid.prefWidth(this)
Layout.preferredHeight : grid.prefHeight(this)
}
}
Button{
width: 100
height: 100
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
onClicked: {
background.visible = !background.visible
}
}
}
From your question it is not clear to me if you want Item 2 to disappear, have its colour blended with background, or have it remain on top when you click the button.

Purpose of z property with real value in QML ListView

In the below sample code, I set z property for the highlight item and depending on the value, it shows up to the user. The z property can also be configured with real value.
It means z value can have fractional values such as 0.1 or 1.2, like that.
Can anyone explain the purpose of z value should be fractional or real value in QML ListView?
import QtQuick 2.8
import QtQuick.Window 2.2
Window {
visible: true
width: 640
height: 480
title: qsTr("Sample List View")
property var delHeight: 50
ListView {
id: listView
anchors.fill: parent
cacheBuffer: 100
footer: Rectangle {
width: (listView.orientation === ListView.Horizontal) ? 200 : parent.width
height: delHeight
color: "lightyellow"
Text {
anchors.centerIn: parent
font.pointSize: 20
text: "Footer"
}
}
header: Rectangle {
width: (listView.orientation === ListView.Horizontal) ? 200 : parent.width
height: delHeight
color: "lightblue"
Text {
anchors.centerIn: parent
font.pointSize: 20
text: "Header"
}
z: 2
}
headerPositioning: ListView.OverlayHeader
highlight: Rectangle {
color: "white"
opacity: 0.5
border.color: "blue"
border.width: 5
z: 1.2
Component.onCompleted: {
console.log ("Created hightlight component with z factor: " + z)
}
}
// highlightMoveDuration: 10000
// highlightRangeMode: ListView.ApplyRange
keyNavigationEnabled: true
model: 20
delegate: componentId
layoutDirection: Qt.RightToLeft
orientation: ListView.Vertical
snapMode: ListView.SnapOneItem
Component.onCompleted: {
currentIndex = 5
}
focus: true
onFocusChanged: {
console.log ("Focus: " + focus)
}
}
Component {
id: componentId
Rectangle {
width: (listView.orientation === ListView.Horizontal) ? 200 : parent.width
height: delHeight
color: "lightgreen"
border.color: "black"
border.width: (listView.currentIndex === index) ? 5 : 1
Text {
anchors.centerIn: parent
font.pointSize: 20
text: "Element: " + index
}
MouseArea {
anchors.fill: parent
onClicked: {
listView.currentIndex = index
}
}
Component.onCompleted: {
console.log ("Created component: " + index)
}
Component.onDestruction: {
console.log ("Destroyed component: " + index)
}
}
}
}
The z property of an item gives the stacking order to that item.
Meaning, if you are constructing two Rectangles one after the other than recently constructed rectangle will be stacked on top the previously constructed one.
Ex code:
Item {
Rectangle {
color: "red"
width: 100; height: 100
}
Rectangle {
color: "blue"
x: 50; y: 50; width: 100; height: 100
}
}
Here red rectangle stacked below blue rectangle.
Now QML gives you chance to change the stacking order through z property of the item.
in the above example if I assign z property of the red rectangle to have a value of anything above 0, I would see it on top of blue rectangle. So z property has changed the stacking order for the sibling item.
The purpose of the z property stays the same in case of ListView highlight. When you want to see the highlight item then you have to give it a value which is greater than the items which will be constructed. You can check this by just setting z property for the componentIds rectangle to some higher value than highlights z value.
NOTE: it only works for sibling items.
More explanation can be found here
Read about the real type here

(QML Calendar Example) Calendar loses ability to alter selection when custom MouseArea is added into delegate's rectangle

I am trying to understand the inner workings of QtQuick/Calendar example.
can be found here:
https://qt-project.org/doc/qt-5/qtquickcontrols-calendar-example.html
and the actual code is in:
https://qt-project.org/doc/qt-5/qtquickcontrols-calendar-qml-main-qml.html
In its dayDelegate it has Rectangle that is defined like this:
dayDelegate: Item {
Rectangle {
anchors.fill: parent
border.color: "transparent"
color: styleData.date !== undefined && styleData.selected ? selectedDateColor : "transparent"
anchors.margins: styleData.selected ? -1 : 0
}
I am trying to add an ability to do custom processing depending on where inside the delegate user clicks. I change the delegate to look like:
dayDelegate: Item {
Rectangle {
anchors.fill: parent
border.color: "transparent"
color: styleData.date !== undefined && styleData.selected ? selectedDateColor : "transparent"
anchors.margins: styleData.selected ? -1 : 0
MouseArea {
anchors.fill: parent
onClicked:
{
dayDelegateText.text = dayDelegateText.text == "two" ? "one" : "two"
}
}
But once I do this, Calendar no longer reacts to clicks outside of currently selected item. What am I breaking by adding this MouseArea?
Even more confusing is that if I add this area inside a rectangle that is a child of delegate's rectangle and invisibly overlaps it everything works as I wanted it to and I can both operate inside a delegate and change selection.
dayDelegate: Item {
Rectangle {
anchors.fill: parent
border.color: "transparent"
color: styleData.date !== undefined && styleData.selected ? selectedDateColor : "transparent"
anchors.margins: styleData.selected ? -1 : 0
Rectangle {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
width: styleData.selected ? parent.width/2 : 0
height:styleData.selected ? parent.height/2 : 0
color: "gray"
MouseArea {
anchors.fill: parent
onClicked:
{
dayDelegateText.text = dayDelegateText.text == "two" ? "one" : "two"
}
}
}
}
It helps to visualise the MouseArea that you added:
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
Rectangle {
width: 300
height: 300
Calendar {
id: calendar
anchors.centerIn: parent
style: CalendarStyle {
dayDelegate: Item {
Rectangle {
id: rect
anchors.fill: parent
Label {
id: dayDelegateText
text: styleData.date.getDate()
anchors.centerIn: parent
horizontalAlignment: Text.AlignRight
font.pixelSize: Math.min(parent.height/3, parent.width/3)
color: styleData.selected ? "red" : "black"
font.bold: styleData.selected
}
MouseArea {
anchors.fill: parent
Rectangle {
anchors.fill: parent
color: "transparent"
border.color: "darkorange"
}
}
}
}
}
}
}
Because you have a MouseArea in every delegate, Calendar's mouse area - a single area that covers all of the day delegates - can't get any mouse events for the areas that are taken by your MouseAreas.
Your third snippet works because you're only taking up half of the area of each delegate - and that's only when that particular day is selected:
import QtQuick 2.3
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.2
Rectangle {
width: 300
height: 300
Calendar {
id: calendar
anchors.centerIn: parent
style: CalendarStyle {
dayDelegate: Item {
Rectangle {
id: rect
anchors.fill: parent
Label {
id: dayDelegateText
text: styleData.date.getDate()
anchors.centerIn: parent
horizontalAlignment: Text.AlignRight
font.pixelSize: Math.min(parent.height/3, parent.width/3)
color: styleData.selected ? "red" : "black"
font.bold: styleData.selected
}
MouseArea {
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
width: styleData.selected ? parent.width / 2 : 0
height: styleData.selected ? parent.height / 2 : 0
Rectangle {
anchors.fill: parent
color: "transparent"
border.color: "darkorange"
}
}
}
}
}
}
}
However, it's hard to suggest a way to achieve what you're after, as you haven't told us what you're trying to do.

Resources