I'm having an issue with ListView. ListView is too long and part of it appears outside of the window but I can't attach a scrollbar. I tried many different combination. I think that problem lies in height parameter but if remove it ListView displays only first entry.
Column{
anchors.fill: parent
Row{
id: buttonsRow
Button{
text: "Open dump file"
onClicked: fileDialog.visible = true
}
Button{
text: "Copy raw data to clipboard"
}
}
ListView{
id: listView
anchors.top: buttonsRow.bottom
height: contentHeight
//clip: true
flickableDirection: Flickable.VerticalFlick
boundsBehavior: Flickable.StopAtBounds
interactive: true
model: ListModel{
id: listModel
}
delegate: MDelegate{}
}
}
Is there any way to make it scrollable?
I don't see, in the code you posted, where you've attached a scrollbar at all. You need to actually include a ScrollBar component in your ListView, like this:
ListView {
id: listView
ScrollBar.vertical: ScrollBar {
active: true
}
}
See "Attaching ScrollBar to a Flickable" at https://doc.qt.io/qt-5/qml-qtquick-controls2-scrollbar.html
Setting height to contentHeight is probably the issue. That would make the ListView as high as all of its item's heights combined. The scrollbar only works when the height of the view is less than the height of its contents.
Here's an approach that uses layouts instead:
import QtQuick 2.8
import QtQuick.Controls 2.1
import QtQuick.Layouts 1.3
ApplicationWindow {
width: 400
height: 300
visible: true
ColumnLayout {
anchors.fill: parent
RowLayout {
id: buttonsRow
Button {
text: "Open dump file"
}
Button {
text: "Copy raw data to clipboard"
}
}
ListView {
id: listView
flickableDirection: Flickable.VerticalFlick
boundsBehavior: Flickable.StopAtBounds
model: 100
clip: true
delegate: ItemDelegate {
text: modelData
}
Layout.fillWidth: true
Layout.fillHeight: true
ScrollBar.vertical: ScrollBar {}
}
}
}
ScrollBar.vertical:ScrollBar{
id: listView
anchors.right: parent.right
visible: listView.contentHeight > listView.height ? true : false
}
Related
I have the list view. When I scroll items the top element can stop any position and can be seen half height. enter image description here
But I need that after scrolling stop the top element can be seen full height.enter image description here
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtQuick.Layouts 1.12
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Scroll")
ColumnLayout {
anchors.fill: parent
RowLayout {
id: buttonsRow
Button {
text: "Open dump file"
}
Button {
text: "Copy raw data to clipboard"
}
}
ListView {
id: listView
flickableDirection: Flickable.VerticalFlick
boundsBehavior: Flickable.StopAtBounds
model: 100
clip: true
delegate: ItemDelegate {
text: modelData
Rectangle
{
width: parent.width - 5
height: parent.height - 5
color: "green"
}
}
Layout.fillWidth: true
Layout.fillHeight: true
ScrollBar.vertical: ScrollBar {}
}
}
}
Use the snapMode property:
ListView {
snapMode: ListView.SnapToItem
// ...
}
My program consisted of a tabbar and stackLayout. I face a layout problem that the tab button is too close to the head of the listview as shown below. They are horizontally aligned together.
But I want the listview to be under the tab button. I tried adding the topMargin in the listview, but it doesn't have any effect at all. Please help.
The code:
import QtQuick 2.9
import QtQuick.Controls 2.2
import QtMultimedia 5.8
import QtQuick.Layouts 1.3
import com.contentplayermod.filemodel 1.0
ApplicationWindow {
visible: true
width: 640
height: 480
title: qsTr("Tabs")
property int idx: 0
property bool isActive: true
TabBar {
id: bar
width: parent.width
TabButton {
text: qsTr("Main")
}
TabButton {
text: qsTr("View")
}
}
StackLayout {
id: stackLayout
height:parent.height
width: parent.width
currentIndex: bar.currentIndex
Item {
id: mainTab
anchors {
topMargin:60
}
width: 500
height:800
ListView {
id: lv
anchors.margins: 50
width: 200; height: 400
highlight: Rectangle { color: "lightsteelblue"; radius: 5 }
focus: true
currentIndex: 0
Component {
id: fileDelegate
Text {
text: fileName
font.pointSize: 20
anchors {
topMargin:60
}
MouseArea{
anchors.fill: parent
}
}
}
model: FileModel{
id: myModel
folder: "c:\\folder"
nameFilters: ["*.mp4","*.jpg"]
}
delegate: fileDelegate
highlightFollowsCurrentItem: true
}
}
Item {
id: viewTab
width: 500
height:800
}
}
}
You can either anchors your stack-top to the bottom of the tab bar like this :
...
StackLayout {
id: stackLayout
height:parent.height - bar.height
anchors.top: bar.bottom
width: parent.width
...
Or much simpler, put everything in a ColumnLayout :
ColumnLayout {
anchors.fill: parent
TabBar {
id: bar
Layout.fillWidth: true
...
}
StackLayout {
id: stackLayout
Layout.fillHeight: true
Layout.fillWidth: true
...
}
}
So you don't have to deal with width and height, and it's more easy to insert new widgets in your window.
You can add spacing to the ColumnLayout to put some space between the TabBar and the content. Or manage this inside the Items displayed by the StackLayout for more flexibility.
I need some help, i have the following code in QML:
import QtQuick 2.9
import QtQuick.Window 2.3
import QtQuick.Layouts 1.3
Window {
visible: true
width: 500
height: 500
ListModel {
id: modeloDeLista
ListElement{
nombre: "Articulo 1"
precio: 5000
descripcion: "Esto es una descripción"
}
ListElement{
nombre: "Articulo 2"
precio: 8000
descripcion: "Esto es una descripción"
}
ListElement{
nombre: "Articulo 3"
precio: 6000
descripcion: "Esto es una descripción"
}
}
Component{
id: vistaLista
Rectangle{
color: "#333"
width: parent.parent.width
height: 70
RowLayout{
Layout.fillWidth: true;
Layout.fillHeight: true;
Text {
text: qsTr("Nombre: "+nombre)
color: "#fff"
Layout.fillWidth: true;
Layout.fillHeight: true;
}
Text {
text: qsTr("Precio: "+precio)
color: "#fff"
Layout.fillWidth: true;
Layout.fillHeight: true;
}
Text {
text: qsTr("Descripcion: "+descripcion)
color: "#fff"
Layout.fillWidth: true;
Layout.fillHeight: true;
}
}
}
}
Rectangle{
id: contenedor
color: "#ddd"
anchors.centerIn: parent
width: parent.width * 0.9
height: parent.height * 0.9
ListView {
spacing: 10
model: modeloDeLista
delegate: vistaLista
anchors.fill: parent
highlightRangeMode: ItemView.NoHighlightRange
}
}
}
this looks like this:
but when you move with the mouse, you pass the gray area that is assigned to you
How do I make it so that it does not get out of there?
I had to put this to allow me to ask the question, because apparently I had little text and more code, so I can ignore this.
Edit
I want to keep the effect but without turning off the scroll
Edit
Here it leaves the container
This is what I need
How do i do it?
If you want to disable the overshoot effect, as indicated by the docs:
boundsBehavior : enumeration
This property holds whether the surface may be dragged beyond the
Flickable's boundaries, or overshoot the Flickable's boundaries when
flicked.
This enables the feeling that the edges of the view are soft, rather
than a hard physical boundary.
The boundsBehavior can be one of:
Flickable.StopAtBounds - the contents can not be dragged beyond the boundary of the flickable, and flicks will not overshoot.
Flickable.DragOverBounds - the contents can be dragged beyond the
boundary of the Flickable, but flicks will not overshoot.
Flickable.OvershootBounds - the contents can overshoot the boundary
when flicked, but the content cannot be dragged beyond the boundary of
the flickable. (since QtQuick 2.5)
Flickable.DragAndOvershootBounds (default) - the contents can be dragged beyond the boundary of the Flickable, and can overshoot the boundary when flicked.
In your case:
ListView {
[...]
boundsBehavior: Flickable.StopAtBounds
}
Update:
You can set the clip property of the Rectangle to true, in your case:
Rectangle{
id: contenedor
color: "#ddd"
anchors.centerIn: parent
width: parent.width * 0.9
height: parent.height * 0.9
clip:true
ListView {
id: list
spacing: 10
model: modeloDeLista
delegate: vistaLista
anchors.fill: parent
}
}
I use QML ScrollView and ListView. ListView consists of headerDelegate and delegate:
ScrollView {
id: scrollView
Layout.fillWidth: true
Layout.fillHeight: true
width: parent.width
height: parent.height
ListView{
id: listView
width: parent.width
height: parent.height
spacing: 10
header: headerDelegate
anchors.fill: parent
property bool isFolded: false
model: MyModel
delegate: mainDelegate
}
}
Everytime ListView is scrolled to the top the first mainDelegate is shown instead of headerDelegate which remains hidden. How can I force the scroll to correctly show headerDelegate?
The problem here is that ScrollView expects child's contentY to be equal 0 but ListView positions the first item of the model at contentY = 0 and places header item before it. If ListView.header is 50px high then it is positioned at ListView.contentY = -50.
The solution that worked for me was to emit ListView.contentYChanged() signal. It causes ScrollView to update. Let me know if this solves your issue.
ScrollView {
id: scrollView
Layout.fillWidth: true
Layout.fillHeight: true
width: parent.width
height: parent.height
ListView{
id: listView
width: parent.width
height: parent.height
spacing: 10
header: headerDelegate
anchors.fill: parent
property bool isFolded: false
model: listModel
delegate: mainDelegate
onContentYChanged: console.log(contentY)
Component.onCompleted: {
contentYChanged()
}
}
}
I've changed listView.contentY manually. After finally loading header (I got event) I've set listView.contentY = 0 - headerDelegateView.height and it works. #Filip Hazubski thank you for good way of solution!
example code
Rectangle
{
id: headerDelegateView
WebEngineView{
...
onLoadingChanged: {
if (loadRequest.status === WebEngineView.LoadSucceededStatus) {
... // here I calculate web page height by java script and set to headerDelegateView.height
listView.contentY = 0 - headerDelegateView.height
}
ScrollView {
...
ListView{
id: listView
...
}
}
}
I'm implementing gesture catcher (swipe left/right) with MouseArea. It should work inside Flickable with vertical flickableDirection. Also it should propagate mouse events to other elements beneath it in visual stack order. The problem is that child mouseArea with propagateComposedEvents set to true is blocking any parent's flicks before exact one click is made. After first click is made it's working correctly. Here is simplified code that is showing this.
import QtQuick 2.4
import QtQuick.Window 2.2
Window {
id: __root
visible: true
width: 460; height: 640
Flickable {
id: mainFlickable
width: parent.width
height: parent.height
contentHeight: column.height
flickableDirection: Flickable.VerticalFlick
MouseArea {
anchors.fill: parent
propagateComposedEvents: true
z: 1
}
Column {
id: column
width: parent.width
Repeater {
model: 5
Rectangle {
width: __root.width
height: 200
color: "yellow"
border.width: 2
MouseArea {
anchors.fill: parent
onClicked: {
console.log("clicked")
}
}
}
} //repeater
} //column
} //flickable
} //window
I spent quite some time trying to fix this and will appreciate any help. Thanks in advance!
I found that following signal handler in MouseArea is a workaround for this and don't break my code:
onReleased: {
if (!propagateComposedEvents) {
propagateComposedEvents = true
}
}
propagateComposedEvents should be set to false on the declaration (or ommited).
Thank you all for the efforts!
I found little workaround for this. Hope it will fit your needs (at least until better solution will be provided).
Here is your updated code:
import QtQuick 2.4
import QtQuick.Window 2.2
Window {
id: __root
visible: true
width: 460; height: 640
Flickable {
id: mainFlickable
width: parent.width
height: parent.height
contentHeight: column.height
flickableDirection: Flickable.VerticalFlick
onDragStarted: ma.enabled = false
onDragEnded: ma.enabled = true
MouseArea {
id: ma
anchors.fill: parent
enabled: false
propagateComposedEvents: true
z: 100
onClicked: {
print("CLICKED ON UPPER")
mouse.accepted = false
}
}
Column {
id: column
width: parent.width
Repeater {
model: 5
Rectangle {
width: __root.width
height: 200
color: "yellow"
border.width: 2
MouseArea {
anchors.fill: parent
onClicked: console.log("clicked on child")
}
}
} //repeater
} //column
} //flickable
} //window