QML: how to scroll scrollview using the mouse wheel - qt

I need to ensure that the ListView scrolls not only when hovering over it, but also in the area around it. As in the picture
I tried to do it like this, but scrolling with the mouse wheel still doesn't work
import QtQuick 2.0
import QtQuick.Controls 2.3
Rectangle {
height: 400
width: 300
color: "steelblue"
ScrollView {
anchors.fill: parent
wheelEnabled: true
ListView {
id: listView
anchors { fill: parent; margins: 40}
clip: true
model: appModel
delegate: Rectangle {
height: 50
width: listView.width
color: colorR
}
}
}
ListModel {
id: appModel
ListElement { colorR: "red"}
ListElement { colorR: "green"}
ListElement { colorR: "blue"}
ListElement { colorR: "cyan"}
ListElement { colorR: "yellow"}
ListElement { colorR: "blue"}
ListElement { colorR: "lightgray"}
ListElement { colorR: "red"}
ListElement { colorR: "green"}
ListElement { colorR: "blue"}
ListElement { colorR: "cyan"}
ListElement { colorR: "yellow"; }
ListElement { colorR: "lightgray"}
}
}

You can use WheelHandler outside the ListView
import QtQuick
import QtQuick.Controls
Rectangle {
height: 400
width: 300
color: "green"
function getRandomColor() {
var letters = '0123456789ABCDEF';
var color = '#';
for (var i = 0; i < 6; i++) {
color += letters[Math.floor(Math.random() * 16)];
}
return color;
}
WheelHandler {
onWheel: (event)=>{listView.flick(0, event.angleDelta.y*event.y)}
}
ListView {
id: listView
anchors { fill: parent; margins: 40}
model: 50
spacing: 10
delegate: Rectangle {
height: 50
width: listView.width
color: getRandomColor()
}
}
}
You can try this online.

Related

Glitching when dragging

I have a very simple code for drag and drop in qml.
But when you are dragging the rectangle while holding mouse the screen of window is glitched! and sometimes the color of some Rectangle vanishes.
Like this bug is reported, but not answered.
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.14
import QtQml.Models 2.1
Window {
id: mainWindow
width: 700
height: 800
visible: true
color: 'grey'
Item {
anchors.fill: parent
GridView {
id: root
width: 320; height: 480
cellWidth: 80; cellHeight: 80
pixelAligned: true
displaced: Transition {
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad }
}
model: DelegateModel {
id: visualModel
model: ListModel {
id: colorModel
ListElement { color: "blue" }
ListElement { color: "green" }
ListElement { color: "red" }
ListElement { color: "yellow" }
ListElement { color: "orange" }
ListElement { color: "purple" }
ListElement { color: "cyan" }
ListElement { color: "magenta" }
ListElement { color: "chartreuse" }
ListElement { color: "aquamarine" }
ListElement { color: "indigo" }
ListElement { color: "black" }
ListElement { color: "lightsteelblue" }
ListElement { color: "violet" }
ListElement { color: "grey" }
ListElement { color: "springgreen" }
ListElement { color: "salmon" }
ListElement { color: "blanchedalmond" }
ListElement { color: "forestgreen" }
ListElement { color: "pink" }
ListElement { color: "navy" }
ListElement { color: "goldenrod" }
ListElement { color: "crimson" }
ListElement { color: "teal" }
}
delegate: DropArea {
id: delegateRoot
width: 80; height: 80
onEntered: visualModel.items.move(drag.source.visualIndex, icon.visualIndex)
property int visualIndex: DelegateModel.itemsIndex
Binding { target: icon; property: "visualIndex"; value: visualIndex }
Rectangle {
id: icon
property int visualIndex: 0
width: 72; height: 72
anchors {
horizontalCenter: parent.horizontalCenter;
verticalCenter: parent.verticalCenter
}
radius: 3
color: model.color
Text {
anchors.centerIn: parent
color: "white"
text: parent.visualIndex
}
DragHandler {
id: dragHandler
}
Drag.active: dragHandler.active
Drag.source: icon
Drag.hotSpot.x: 36
Drag.hotSpot.y: 36
states: [
State {
when: icon.Drag.active
ParentChange {
target: icon
parent: root
}
AnchorChanges {
target: icon
anchors.horizontalCenter: undefined
anchors.verticalCenter: undefined
}
}
]
}
}
}
}}
}
Before:
After:
With add attribute of open-gl in main.cpp
QCoreApplication::setAttribute(Qt::AA_UseOpenGLES);
#SAt looks like you found the issue with your rendering engine. Sometimes there are quirks like that in your graphics card and may require updating your graphics driver. Otherwise, as you found, see the other rendering options with QCoreApplication::setAttribute() or by setting the QT_OPENGL environment variable:
Qt::AA_UseDesktopOpenGL Equivalent to setting QT_OPENGL to desktop.
Qt::AA_UseOpenGLES Equivalent to setting QT_OPENGL to angle.
Qt::AA_UseSoftwareOpenGL Equivalent to setting QT_OPENGL to software.
References:
https://doc.qt.io/qt-6/qcoreapplication.html#setAttribute
https://doc.qt.io/qt-6/qt.html#ApplicationAttribute-enum
https://doc.qt.io/qt-5/windows-requirements.html#graphics-drivers
I test your code in my system and it works well.
My OS is Ubuntu 20.04.
My Qt Version is 5.15.2 and 6.2.3 I checked in both.
This is the Result:

how to keep yellow Rectangle in my demo code can't be moved?

This demo is from official demo of drag and drop.
I have changed a little. Now when other rectangle enterd the mousearea including the yellow rectangle, the yellow rectangle won't move. And yellow rectangle itself can't be draged too.
but when I drag cyan into the area between the green rec and the red one or other rectangle which is not in the area including the yellow rec, the yellow rectangle will move. It's not OK.
how can I fix that?
I already google, don't know which keyword to google.
import QtQuick 2.10
import QtQuick.Window 2.10
import QtQml.Models 2.1
import QtQuick.Controls 2.1
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
GridView {
id: root
width: 320; height: 480
cellWidth: 80; cellHeight: 80
displaced: Transition {
NumberAnimation { properties: "x,y"; easing.type: Easing.OutQuad
}
}
//! [0]
model: DelegateModel {
//! [0]
id: visualModel
model: ListModel {
id: colorModel
ListElement { color1: "blue" }
ListElement { color1: "green" }
ListElement { color1: "red" }
ListElement { color1: "yellow" }
ListElement { color1: "orange" }
ListElement { color1: "purple" }
ListElement { color1: "cyan" }
ListElement { color1: "magenta" }
ListElement { color1: "chartreuse" }
ListElement { color1: "aquamarine" }
ListElement { color1: "indigo" }
ListElement { color1: "black" }
ListElement { color1: "lightsteelblue" }
ListElement { color1: "violet" }
ListElement { color1: "grey" }
ListElement { color1: "springgreen" }
ListElement { color1: "salmon" }
ListElement { color1: "blanchedalmond" }
ListElement { color1: "forestgreen" }
ListElement { color1: "pink" }
ListElement { color1: "navy" }
ListElement { color1: "goldenrod" }
ListElement { color1: "crimson" }
ListElement { color1: "teal" }
}
//! [1]
delegate: MouseArea {
id: delegateRoot
//property int visualIndex: DelegateModel.itemsIndex
property int visualIndex: DelegateModel.itemsIndex
width: 80;
height: 80
drag.target: icon
Rectangle {
id: icon
width: 72; height: 72
anchors {
horizontalCenter: parent.horizontalCenter;
verticalCenter: parent.verticalCenter
}
color: model.color1
radius: width/2
Drag.active: delegateRoot.drag.active
Drag.source: delegateRoot
Drag.hotSpot.x: 36
Drag.hotSpot.y: 36
states: [
State {
when: icon.Drag.active
ParentChange {
target: icon
parent: delegateRoot //root
}
AnchorChanges {
target: icon;
anchors.horizontalCenter: {
if(color1 === "yellow"){
return parent.horizontalCenter;
}
else
undefined
}
anchors.verticalCenter: {
if(color1 === "yellow"){
return parent.verticalCenter
}
else
undefined
}
}
}
]
}
DropArea {
anchors { fill: parent; margins: 15 }
onEntered:{
console.log("enter " + color1)
if(color1 === "yellow")
return //console.log("enter " + iconname)
else
visualModel.items.move(drag.source.visualIndex, delegateRoot.visualIndex)
}
}
}
//! [1]
}
}
}
offical demo name is draganddrop. gridview.qml
EDIT
so this is kind of a hacky solution, but it is simple and it gets the job done.
What I basically did, is to iterate over the items after each movement and put yellow back in case it changed position.
DropArea {
anchors { fill: parent; margins: 15 }
onEntered:{
console.log("enter " + color1)
if(color1 === "yellow")
return //console.log("enter " + iconname)
else {
visualModel.items.move(drag.source.visualIndex, delegateRoot.visualIndex)
for (var i = 0; i< visualModel.items.count; i++)
{
if (visualModel.items.get(i).model.color1 === "yellow") {
visualModel.items.move(i, 3)
return;
}
}
}
}
}

Horizontal listview navigation - visible item

I have more horizontal listview. For example let's take two of them. Items of each list are not the same length, when one list is scrolling - the other one does, too. I've solved that with contentX property. But, when I want to navigate between each other (when I press key "down" I need to force focus second listview). The problem is that focus is on horizontalna2.currentIndex that is remembered, and I want to go on first visible item in listview.
In android is that very simple, but to solve that here, huh..
Here is sketch of the code:
Rectangle {
width: 500
height: 200
ListModel {
id: model1
ListElement { itemwidth: 100 }
ListElement { itemwidth: 200 }
ListElement { itemwidth: 50 }
ListElement { itemwidth: 70 }
ListElement { itemwidth: 90 }
ListElement { itemwidth: 90 }
ListElement { itemwidth: 90 }
ListElement { itemwidth: 90 }
ListElement { itemwidth: 90 }
ListElement { itemwidth: 90 }
}
ListModel {
id: model2
ListElement { itemwidth: 300 }
ListElement { itemwidth: 50 }
ListElement { itemwidth: 70 }
ListElement { itemwidth: 100 }
ListElement { itemwidth: 90 }
ListElement { itemwidth: 30 }
ListElement { itemwidth: 90 }
ListElement { itemwidth: 90 }
ListElement { itemwidth: 90 }
ListElement { itemwidth: 90 }
}
ListView {
clip: true
id: horizontalna
boundsBehavior: Flickable.StopAtBounds
width: 500
height: 60;
focus: true
model: model1
orientation: ListView.Horizontal
KeyNavigation.down: horizontalna2
onContentXChanged: {
if (horizontalna.activeFocus === true)
{
horizontalna2.contentX = horizontalna.contentX
}
}
delegate: Item {
id: containerHorizontal
width: itemwidth; height: 60;
Rectangle {
id: contentHorizontal
anchors.centerIn: parent; width: containerHorizontal.width; height: containerHorizontal.height - 10
color: "transparent"
antialiasing: true
Rectangle { id: insideConHorizontal; anchors.fill: parent; anchors.margins: 3; color: "grey"; antialiasing: true; radius: 5
Text {
id: labelHorizontal
text: "name"
color: "white"
}
}
}
states: State {
name: "active"; when: containerHorizontal.activeFocus
PropertyChanges { target: contentHorizontal; color: "#FFFF00"; scale: 1}
PropertyChanges { target: insideConHorizontal; color: "#F98F06" }
PropertyChanges { target: labelHorizontal; color: "#0E2687"}
}
}
}
ListView {
id: horizontalna2
anchors.top: horizontalna.bottom
boundsBehavior: Flickable.StopAtBounds
width: 500
height: 60;
focus: true
model: model2
orientation: ListView.Horizontal
onContentXChanged: {
if (horizontalna2.activeFocus === true)
{
horizontalna.contentX = horizontalna2.contentX
}
}
delegate: Item {
id: containerHorizontal2
width: itemwidth; height: 60;
Rectangle {
id: contentHorizontal2
anchors.centerIn: parent; width: containerHorizontal2.width; height: containerHorizontal2.height - 10
color: "transparent"
antialiasing: true
Rectangle { id: insideConHorizontal2; anchors.fill: parent; anchors.margins: 3; color: "grey"; antialiasing: true; radius: 5
Text {
id:labelHorizontal2
color: "white"
text: "name"
}
}
}
states: State {
name: "active"; when: containerHorizontal2.activeFocus
PropertyChanges { target: contentHorizontal2; color: "#FFFF00"; scale: 1}
PropertyChanges { target: insideConHorizontal2; color: "#F98F06" }
PropertyChanges { target: labelHorizontal2; color: "#0E2687"}
}
}
}
}
EDIT[SOLVED] :
Get index of first visible item of second list depending on contentX --> function indexAt()
onCurrentIndexChanged: {
if (horizontalna.activeFocus === true)
{
horizontalna2.currentIndex = horizontalna2.indexAt((horizontalna2.contentX),0)
}
}
Get index of first visible item of second list depending on contentX --> function indexAt()
onCurrentIndexChanged: {
if (horizontalna.activeFocus === true)
{
horizontalna2.currentIndex = horizontalna2.indexAt((horizontalna2.contentX),0)
}
}

QML: ScrollView with GridView inside: adjust cell to available space (with or without scroll bar)

I have a QML ScrollView with a GridView inside (rectangles in 3 columns) and I have a repaint problem when the scroll appears/disappears.
The window has fixed width (300) and variable height, so the scroll appears when window height is less than content height, of course.
My target is that the rectangles are completely visibles always (with or without scroll), expanded to the left when no scroll appears, and to the left of the scroll when it is visible. For that, I suppose I need to set the cell size depending on the scroll, for them to adjust the available space.
It works BUT just in the moment the scroll appears/disappears, there is a short window height range when the rectangles are not painted properly.
Here is my code, I have tried with other properties otions with no success...
import QtQuick 2.5
import QtQuick.Controls 1.3
import QtQuick.Controls.Styles 1.4
Item {
id: idGrid
height: 800
width: 300
property int iNumcolums: 3
property int iMarginGrid: 2
ListModel {
id: appModel
ListElement { colorR: "red"}
ListElement { colorR: "green" }
ListElement { colorR: "blue" }
ListElement { colorR: "cyan"}
ListElement { colorR: "yellow"}
ListElement { colorR: "blue" }
ListElement { colorR: "lightgray" }
ListElement { colorR: "red" }
ListElement { colorR: "green" }
ListElement { colorR: "blue" }
ListElement { colorR: "cyan" }
ListElement { colorR: "yellow" }
ListElement { colorR: "lightgray" }
ListElement { colorR: "blue" }
}
ScrollView {
id: scrollView
anchors.top: parent.top
anchors.bottom: parent.bottom
anchors.left: parent.left
anchors.right: parent.right
anchors.leftMargin: iMarginGrid
anchors.rightMargin: iMarginGrid
property int scrollWidth: 10
style: ScrollViewStyle {
id: sptScrollStyle
property int iScrollWidth: 10
handle: Rectangle {
implicitWidth: iScrollWidth
color: "gray"
radius: 20
}
scrollBarBackground: Rectangle {
implicitWidth: iScrollWidth
color: "lightgray"
radius: 20
}
decrementControl: Rectangle {
implicitWidth: 0
}
incrementControl: Rectangle {
implicitWidth: 0
}
}
GridView {
id: grid
//width: parent.width;
height: parent.height
model: appModel
property bool scrollBarVisible: contentHeight > height
width: parent.width - (scrollBarVisible ? scrollView.iScrollWidth : 0)
property int iSizeThumb: width / 3
cellWidth: iSizeThumb; cellHeight: iSizeThumb
delegate: Item {
width: grid.cellWidth; height: grid.cellHeight
Rectangle { color: colorR; anchors.fill: parent; anchors.margins: 2}
}
}
}
}
}

QML Nested List view with Highlight

I need to create nested list view and as shown below, and highlight the main list and sub-list with different color
I have tried with ListView highlight but there are issue like the highlight showing for child as well as parent as shown
below image.
I am using the code from here with some minor modification.
Here is the full code
import QtQuick 2.2
import QtQuick.Controls 1.1
import QtQuick 2.2
import QtQuick.Controls 1.2
import QtQuick.Controls.Styles 1.1
ApplicationWindow {
id: loginWindow
//visibility: "Maximized"
visible: true
width: 720
height: 720
Item {
width: 200
height: 720
ListView {
id: list
anchors.fill: parent
model: nestedModel
delegate: categoryDelegate
highlight: Rectangle {
color: "#FF00AAFF" //"#FF59ACFF";
radius: 2
}
}
ListModel {
id: nestedModel
ListElement {
categoryName: "Veggies"
collapsed: true
// A ListElement can't contain child elements, but it can contain
// a list of elements. A list of ListElements can be used as a model
// just like any other model type.
subItems: [
ListElement {
itemName: "Tomato"
},
ListElement {
itemName: "Cucumber"
},
ListElement {
itemName: "Onion"
},
ListElement {
itemName: "Brains"
}
]
}
ListElement {
categoryName: "Fruits"
collapsed: true
subItems: [
ListElement {
itemName: "Orange"
},
ListElement {
itemName: "Apple"
},
ListElement {
itemName: "Pear"
},
ListElement {
itemName: "Lemon"
}
]
}
ListElement {
categoryName: "Cars"
collapsed: true
subItems: [
ListElement {
itemName: "Nissan"
},
ListElement {
itemName: "Toyota"
},
ListElement {
itemName: "Chevy"
},
ListElement {
itemName: "Audi"
}
]
}
}
Component {
id: categoryDelegate
Column {
width: 200
Rectangle {
id: categoryItem
border.color: "black"
border.width: 5
color: "#33FF5225"
height: 50
width: 200
Text {
anchors.verticalCenter: parent.verticalCenter
x: 15
font.pixelSize: 24
text: categoryName
}
Rectangle {
color: "red"
width: 30
height: 30
anchors.right: parent.right
anchors.rightMargin: 15
anchors.verticalCenter: parent.verticalCenter
MouseArea {
anchors.fill: parent
// Toggle the 'collapsed' property
onClicked: {
list.currentIndex = index
nestedModel.setProperty(index, "collapsed",
!collapsed)
}
}
}
}
Loader {
id: subItemLoader
// This is a workaround for a bug/feature in the Loader element. If sourceComponent is set to null
// the Loader element retains the same height it had when sourceComponent was set. Setting visible
// to false makes the parent Column treat it as if it's height was 0.
visible: !collapsed
property variant subItemModel: subItems
sourceComponent: collapsed ? null : subItemColumnDelegate
onStatusChanged: if (status == Loader.Ready) item.model = subItemModel
}
}
}
Component {
id: subItemColumnDelegate
Column {
property alias model: subItemRepeater.model
width: 200
Repeater {
id: subItemRepeater
delegate: Rectangle {
x: 10
color: "#33FF5225"
height: 40
width: 190
border.color: "black"
border.width: 2
Text {
anchors.verticalCenter: parent.verticalCenter
x: 30
font.pixelSize: 18
text: itemName
}
}
}
}
}
}
}
How can I overcome this issue. Basically I need to highlight Parent and child Item with different color.
Edit:
I can highlight parent list using the code
color:categoryDelegate.ListView.isCurrentItem ? "#FF00AAFF" : "#CCBBBBBB"
but coud'nt a find similar way to change the color of child list (sub list) on click.
Change the color property of the delegate in subItemRepeater to your choice.
Example
Component {
id: subItemColumnDelegate
Column {
...
Repeater {
id: subItemRepeater
delegate: Rectangle {
...
color: "purple"
...
}
}
}
}
Similarly change the color property categoryItem in the categoryDelegate.
Example
Component {
id: categoryDelegate
Column {
...
Rectangle {
id: categoryItem
...
color: "blue"
...
}
}
}
EDIT:
In that case the the overall concept is wrong. In the comment of the original code the author has written A ListElement can't contain child elements, but it can contain a list of elements. So we can't highlight the child item. But the following approach will give good result to you.
import QtQuick 2.0
Rectangle {
width: 360
height: 360
ListModel {
id: model1
ListElement {
name: "name"
}
ListElement {
name: "name"
}
ListElement {
name: "name"
}
}
ListModel {
id: model2
ListElement {
name: "inside"
}
ListElement {
name: "inside"
}
ListElement {
name: "inside"
}
}
ListView {
id: outer
model: model1
delegate: listdelegate
anchors.fill: parent
}
Component {
id: listdelegate
Item {
width: 100
height: col.childrenRect.height
Column {
id: col
anchors.left: parent.left
anchors.right: parent.right
Text {
id: t1
text: name
}
ListView {
id: insidelist
model: model2
property int collapseHeightFlag: childrenRect.height
delegate: Component {
id: delegate2
Item {
width: 100
height: col2.childrenRect.height
Column {
id: col2
anchors.left: parent.left
anchors.right: parent.right
Text {
id: name1
text: name
}
}
MouseArea {
anchors.fill: parent
onClicked: {
insidelist.currentIndex = index;
}
}
}
}
contentHeight: contentItem.childrenRect.height
height: 0
anchors.left: parent.left
anchors.right: parent.right
clip: true
highlight: Rectangle {
color: "pink"
radius: 2
}
focus: true
}
}
Rectangle {
color: "red"
width: 10
height: 10
anchors.right: parent.right
anchors.rightMargin: 5
anchors.top: parent.top
anchors.topMargin: 5
MouseArea {
anchors.fill: parent
onClicked: {
if(insidelist.height === insidelist.collapseHeightFlag) {
insidelist.height = 0;
}
else
insidelist.height = insidelist.collapseHeightFlag;
}
}
}
}
}
}

Resources