I have a simple ListView. My goal is to use two buttons to scroll the view by one row.
I tried with ScrollBar.vertical.position or ScrollBar.increase() but I'm not able to scroll items one by one.
This is the code:
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
import QtQuick.VirtualKeyboard 2.15
Window {
id: window
width: 640
height: 480
visible: true
ListModel {
id: contactModel
ListElement {
name: "Bill Smith"
number: "555 3264"
}
ListElement {
name: "John Brown"
number: "555 8426"
}
ListElement {
name: "Sam Wise"
number: "555 0473"
}
ListElement {
name: "Gollum"
number: "555 3473"
}
ListElement {
name: "Bill Smith"
number: "555 3264"
}
ListElement {
name: "John Brown"
number: "555 8426"
}
ListElement {
name: "Sam Wise"
number: "555 0473"
}
ListElement {
name: "Gollum"
number: "555 3473"
}
ListElement {
name: "Bill Smith"
number: "555 3264"
}
ListElement {
name: "John Brown"
number: "555 8426"
}
ListElement {
name: "Sam Wise"
number: "555 0473"
}
ListElement {
name: "Gollum"
number: "555 3473"
}
ListElement {
name: "Bill Smith"
number: "555 3264"
}
ListElement {
name: "John Brown"
number: "555 8426"
}
ListElement {
name: "Sam Wise"
number: "555 0473"
}
ListElement {
name: "Gollum"
number: "555 3473"
}
}
Component {
id: contactDelegate
Item {
width: window.width
height: 40
Column {
Text {
text: '<b>Name:</b> ' + name
}
Text {
text: '<b>Number:</b> ' + number
}
}
Rectangle {
width: parent.width
height: 1
color: "black"
}
}
}
Column {
anchors.fill: parent
spacing: 10
ListView {
width: parent.width
height: parent.height - 80
model: contactModel
delegate: contactDelegate
clip: true
highlight: Rectangle {
color: "lightsteelblue"
radius: 5
}
ScrollBar.vertical: ScrollBar {
snapMode: ScrollBar.SnapAlways
policy: ScrollBar.AlwaysOn
}
focus: true
}
Row {
anchors.horizontalCenter: parent.horizontalCenter
spacing: 10
Button {
width: 150
height: 40
text: "Scroll UP"
}
Button {
width: 150
height: 40
text: "Scroll Down"
}
}
}
}
Since you know the height of a single row, you can simply manually adjust the contentY property of the ListView.
First, give the ListView an id.
ListView {
id: lv
...
}
Then update the contentY of your ListView whenever the Buttons are pressed:
Button {
width: 150
height: 40
text: "Scroll UP"
onClicked: {
lv.contentY -= 40
}
}
Button {
width: 150
height: 40
text: "Scroll Down"
onClicked: {
lv.contentY += 40
}
}
Related
In my screen, I can see around 5 list element out of 11.I'm Using Up/Down Arrow Keys to move the Highlight Rectangle(Border Rectangle).
Highlight rectangle will be displayed above list element only for first 5 list elements.
Once it reaches the 6th element the rectangle will be displayed behind the list element even if the Z index is 1 and it never comes above list element again.
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.4
import QtQuick.Layouts 1.3
import QtGraphicalEffects 1.0
Window {
visible: true
width: Screen.width
height: Screen.height
id: rootWindow
ListModel {
id: contact
ListElement {
name: "John Brown"
number: "555 8426"
}
ListElement {
name: "Sam Wise"
number: "555 0473"
}
ListElement {
name: "Bill Smith"
number: "555 3264"
}
ListElement {
name: "John Brown"
number: "555 8426"
}
ListElement {
name: "Sam Wise"
number: "555 0473"
}
ListElement {
name: "Bill Smith"
number: "555 3264"
}
ListElement {
name: "Sam Wise"
number: "555 0473"
}
ListElement {
name: "Bill Smith"
number: "555 3264"
}
ListElement {
name: "John Brown"
number: "555 8426"
}
ListElement {
name: "Sam Wise"
number: "555 0473"
}
ListElement {
name: "Bill Smith"
number: "555 3264"
}
}
ListView{
clip: true
z: -1
id: lst
width: Screen.width
height: Screen.height
anchors.centerIn: rootWindow
x: rootWindow.width *.05
spacing: 20
y: subrect.height + subrect.y+ 100
model: contact
delegate:
RowLayout{
id: idx
anchors.topMargin: 5
spacing: -5
Rectangle{
width: 30
height:100
color: "#3399ff"
radius: 5
}
Rectangle{
id: segment
width: lst.width
height: 100
color: "white";
layer.enabled: true
layer.effect: DropShadow{
transparentBorder: true
horizontalOffset: 3
verticalOffset: 3
color: "#e1dede"
}
RowLayout {
Rectangle{
id: inner
width: 300
height: 50
color: "transparent"
Text {
x: 50
y: inner.height /3
text: "Name : " + name
font.pixelSize: 30
anchors.verticalCenter: inner
}
Column{
y: inner.height /3
Text {
color: "grey"
x: lst.width * .8
text: "Contact "
font.pixelSize: 20
}
Text {
color: "grey"
font.pixelSize: 20
x: lst.width * .8
text: number
}
}
}
}
}
}
focus: true
highlight: Rectangle { color: "transparent"; z:1;radius: 8; border.width: 3; border.color: "black" }
}
}
Thank You
The stacking order of the Listview happens as below.
So to get your highlighter on the top change z: 2 that should work. Here is the complete description of the Listview stacking order doc.
And remove the z-order of your listview's instance.
I have a vertical Listview and when i click an item i will display horizontal Listview. The question is that when i click 2 nd item i should display 2nd item on horizontal Listview. Here it is my implementation:
main.qml
import QtQuick 2.7
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
ApplicationWindow {
id: root
visible: true
width: 640
height: 480
title: qsTr("Hello World")
StackView {
id: rootStackView
anchors.fill: parent
initialItem: verListView
}
VListview {
id: verListView
onListItemClicked: {
rootStackView.push(horListView)
horListView.init(index)
}
}
HListView {
id: horListView
visible: false
}
}
VListview.qml
import QtQuick 2.0
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
Page {
id: root
signal listItemClicked(var index)
ListView {
id: listView
anchors.fill: parent
Layout.fillWidth: true
model: ListModel {
ListElement {
name: "Bill Smith"
number: "555 3264"
}
ListElement {
name: "John Brown"
number: "555 8426"
}
ListElement {
name: "Sam Wise"
number: "555 0473"
}
}
delegate: Component {
id: contactDelegate
Item {
MouseArea {
anchors.fill: parent
onClicked: {
console.log("aaa")
root.listItemClicked(index)
}
}
width: listView.width; height: 40
Column {
Text { text: '<b>Name:</b> ' + name }
Text { text: '<b>Number:</b> ' + number }
}
}
}
}
}
HListview.qml
import QtQuick 2.0
import QtQuick.Controls 2.0
import QtQuick.Layouts 1.0
Page {
function init(index) {
console.log(index)
horizontalListView.currentIndex = index;
horizontalListView.positionViewAtIndex(index, ListView.Beginning)
}
ListView {
id: horizontalListView
anchors.fill: parent
orientation: ListView.Horizontal
model: ListModel {
ListElement {
name: "Bill Smith"
number: "555 3264"
}
ListElement {
name: "John Brown"
number: "555 8426"
}
ListElement {
name: "Sam Wise"
number: "555 0473"
}
}
snapMode: ListView.SnapToItem
delegate: Component {
id: contactDelegate
Item {
width: horizontalListView.width; height: 40
Column {
Text { text: '<b>Name:</b> ' + name }
Text { text: '<b>Number:</b> ' + number }
}
}
}
}
}
HorizontalListView
I am clicking 2nd and 3 rd items but it display always first item. Anybody faced the issue? Thanks in advance
The width of horizontalListView is wrongly set.
HListview.qml
ListView {
id: horizontalListView
// anchors.fill: parent
height: 40 <== fix the height
width: root.width <== width of the hview must be same size as that of root window.
orientation: ListView.Horizontal
...
}
EDIT
Explanation: If positioning the view at index would cause empty space to be displayed at the beginning or end of the view, the view will be positioned at the boundary.
I want to disable the dragging of my List view using pressing and holding a mouse button while moving the cursor. I am trying to implement some other feature such as multiple selection using this command. I would only like the scrolling to be enabled. The interactive property of the flickable totally disables the movement of the view. Is there some workaround for this?
I guess there are some ways to achieve what you need, but the following solution works.
The idea is to have a MouseArea and set the interactive property to false when the signals onPressed and onClicked are emitted. interactive should be set to true again in the onReleased handler.
import QtQuick 2.5
import QtQuick.Window 2.2
import QtQuick.Controls 1.4
Window {
visible: true
width: 640
height: 480
title: qsTr("Hello World")
ListModel {
id: listModel
ListElement {
name: "ttt"
number: "111"
}
ListElement {
name: "rrr"
number: "222"
}
ListElement {
name: "sss"
number: "333"
}
ListElement {
name: "xxx"
number: "444"
}
ListElement {
name: "yyy"
number: "555"
}
ListElement {
name: "zzz"
number: "666"
}
ListElement {
name: "aaa"
number: "777"
}
ListElement {
name: "bbb"
number: "888"
}
ListElement {
name: "ccc"
number: "999"
}
ListElement {
name: "ddd"
number: "011"
}
ListElement {
name: "eee"
number: "022"
}
ListElement {
name: "fff"
number: "033"
}
}
ListView {
id: myList
width: 180; height: 100
clip: true
Component {
id: contactsDelegate
Rectangle {
id: wrapper
width: 180
height: contactInfo.height
color: "lightblue"
Text {
id: contactInfo
text: name + ": " + number
color: "black"
}
MouseArea {
anchors.fill: parent
onPressed: {
myList.interactive = false
console.debug("onPressed")
}
onClicked: {
myList.interactive = false
console.debug("onClicked")
}
onReleased: {
myList.interactive = true
console.debug("onReleased")
}
}
}
}
model: listModel
delegate: contactsDelegate
focus: true
}
}
I'm going to write a touchscreen application that has a movable listView control. Currently my problem is that the content comes out of the view, if the content is longer/highter than the listView itself when I try to scroll.
This is my current code. I need a solution only to scroll within the listview and not to overflow its border.
ListModel {
id: listModle
ListElement {
name: "Bill Smith"
number: "555 3264"
}
ListElement {
name: "John Brown"
number: "555 8426"
}
ListElement {
name: "Sam Wise"
number: "555 0473"
}
ListElement {
name: "Bill Smith"
number: "555 3264"
}
ListElement {
name: "John Brown"
number: "555 8426"
}
ListElement {
name: "Sam Wise"
number: "555 0473"
}
}
Rectangle {
x: 100
y: 100
width: 180; height: 200
Component {
id: contactDelegate
Item {
width: 180; height: 40
Column {
Text { text: '<b>Name:</b> ' + name }
Text { text: '<b>Number:</b> ' + number }
}
}
}
ListView {
id: listView
anchors.fill: parent
model: listModle
delegate: contactDelegate
//highlight: Rectangle { color: "lightsteelblue"; radius: 5 }
focus: true
contentHeight: 150
}
}
listView exceedes the Rectangle parent because there are too many elements to display.
That's perfectly fine, you simply have to turn clip: true on your Rectangle object. That way, the content of your list will be visible only from the Rectangle viewport.
Edit (pro-tip): if the listview height is less than the enclosing parent Rectangle, for usability concerns you should disable the scroll behavior. Look at Qml Flickable API(especially interactive and contentWidth/Height ) to perform some simple check ;)
To implement someting like a scroll index you can use:
ListView.visibleArea.yPosition
which gives the Y position in percent.
Does anybody knows, how to prevent scrolling down QML ListView when I prepend some elements to its head? I want to update ListView in a Twitter-like manner, when it always keeps its position and only explicit flick is possible.
Actually the insert function did the job. You can insert it at the top or any desired position like this modelName.insert(0,{object});. A working example is here.
import QtQuick 1.0
Rectangle {
id: rectangle1
width: 320
height: 480
ListModel {
id: cModel
ListElement {
name: "Bill Smith"
number: "555 3264"
}
ListElement {
name: "John Brown"
number: "555 8426"
}
ListElement {
name: "Sam Wise"
number: "555 0473"
}
}
ListView {
id: list_view1
width: rectangle1.width
height: rectangle1.height - 40
anchors.horizontalCenter: parent.horizontalCenter
delegate: Text {
text: name + ": " + number
}
model: cModel
}
Rectangle {
id: rectangle2
width: 320
height: 40
color: "#ffffff"
anchors.top: list_view1.bottom
Text {
id: text1
text: qsTr("Click to add!")
anchors.horizontalCenter: parent.horizontalCenter
anchors.verticalCenter: parent.verticalCenter
font.pixelSize: 16
MouseArea {
id: mouse_area1
anchors.fill: parent
onClicked: addNewItemTop();
}
}
}
function addNewItemTop()
{ var i = Math.random();
cModel.insert(0,{"name" : "New Number", "number":i.toString()});
}
}