I have a ListView in my qml file, but when I am overscrolling it, it gets stuck for a several seconds and then flicks back. Does anyone know what can be the reason of that delay before flicking back?
Also, it's only freezes, when the text inside my delegates is on Russian language. On english it works fine
Upd:
There is nothing specific, but minimal, reproducible example:
ListView {
id: list
anchors {
right: parent.right
top: parent.top
}
height: parent.height
width: 502
interactive: height < contentHeight
spacing: 24
currentIndex: -1
footer: Item {
height: 100
}
delegate: Item {
anchors {
left: list.contentItem.left
right: list.contentItem.right
leftMargin: 40
rightMargin: 40
}
implicitHeight: Math.max(image.height, description.implicitHeight)
// Some other code
}
ScrollBar.vertical: OknaGui.ScrollBar { id: scrollBar } // Just a scrollbar
}
This might not be the proper solution, but you can disable overscroll at all with boundsBehavior: Flickable.StopAtBounds
Related
Window {
id: mainWindow
width: 960
height: 600
flags: Qt.FramelessWindowHint | Qt.WindowMinimizeButtonHint | Qt.Window
Rectangle {
width: 15
height: 15
anchors {
top: parent.top
left: parent.left
topMargin: 10
leftMargin: 910
}
SvgImage {
width: 11
height: 2
source: "images/Collapse.svg"
anchors {
centerIn: parent
}
}
MouseArea {
id: mouse
anchors {
fill: parent
}
onPressed: {
mainWindow.showMinimized()
}
}
Timer {
repeat: true
interval: 1000
running: true
onTriggered: {
console.log("mouse.pressed = ", mouse.pressed);
}
}
}
}
I faced an issue with Qt.FramelessWindowHint. After using showMinimized() function I restore the window but then any click on window causes minimizing window again. mouseArea never gets pressed. I tried putting Timer printing mouse.pressed valueand it's false all the time.
I found the several links on this issue but there's no solution except going to fullscreen when restoring window. My application always stays the same size and never goes to fullscreen.
https://www.qtcentre.org/threads/33298-Qt-FramelessWindowHint-qgraphicsview-qgraphicwidget-showminimized-problem
https://www.qtcentre.org/threads/42641-QML-rendering-problems-after-showMinimized()
QML: rendering problems after showMinimized()
Maybe you could give me a hint for workaround. Btw I'm using Qt 5.15
Use onClicked insted of onPressed inside the MouseArea.
In fact, I could not see any windows after running your code
I add visible: true and I removed SvgImage.
This is what I run:
import QtQuick 2.15
import QtQuick.Window 2.15
Window {
id: mainWindow
width: 960
height: 600
visible: true
flags: Qt.FramelessWindowHint | Qt.WindowMinimizeButtonHint | Qt.Window
Rectangle {
width: 15
height: 15
color: "#f50909"
anchors {
top: parent.top
left: parent.left
topMargin: 10
leftMargin: 910
}
MouseArea {
id: mouse
anchors {
fill: parent
}
onPressed: {
mainWindow.showMinimized()
}
}
}
}
This is my result and it works correctly:
I have a QML ListView, and I'm trying to dynamically add elements to it. I want the background rectangle to also scale dynamically as elements are added/removed from the ListView. Right now I get a binding loop, and I understand what they are but I can't figure out where it's coming from. I played around changing the code a bit and I was able to get rid of the binding loop one time but then the ListView couldn't be scrolled. Anyone have any ideas?
import QtQuick 2.15
import QtQuick.Window 2.0
Window {
visible: true
width: 800
height: 800
Rectangle {
id: listContainer
height: childrenRect.height
width: parent.width
color: "transparent"
anchors {
top: parent.top
topMargin: 30
left: parent.left
leftMargin: 45
}
ListView {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
model: myModel
height: childrenRect.height
header:
Text {
z: 2
height: 50
text: "HEADER"
color: "black"
}
delegate: Component {
Item {
Text {
id: userName;
text: name;
color: "black";
font.pixelSize: 50
anchors {
left: parent.left
leftMargin: 20
}
}
Rectangle {
height: 1
color: 'black'
width: listContainer.width
anchors {
left: userName.left
top: userName.top
topMargin: - 12
leftMargin: -15
}
}
}
}
spacing: 80
}
}
ListModel {
id: myModel
}
/* Fill the model with default values on startup */
Component.onCompleted: {
for (var i = 0; i < 100; i++) {
myModel.append({
name: "Big Animal : " + i
})
}
}
}
EDIT: As suggested by #Aditya, the binding loop can be removed by having a static ListView height, but I don't want it to be that way. I'm using the rectangle as a background for the ListView and I want it to scale according to the ListView. For example, if I only add two elements, I want the rectangle to also scale for those two elements and not cover the entire screen. This causes a problem:
import QtQuick 2.15
import QtQuick.Window 2.0
Window {
visible: true
width: 800
height: 800
Rectangle {
id: listContainer
height: childrenRect.height
width: parent.width
color: "yellow"
anchors {
top: parent.top
topMargin: 30
left: parent.left
leftMargin: 45
}
ListView {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
model: myModel
height: 800//childrenRect.height
header:
Text {
z: 2
height: 50
text: "HEADER"
color: "black"
}
delegate: Component {
Item {
Text {
id: userName;
text: name;
color: "black";
font.pixelSize: 50
anchors {
left: parent.left
leftMargin: 20
}
}
Rectangle {
height: 1
color: 'black'
width: listContainer.width
anchors {
left: userName.left
top: userName.top
topMargin: - 12
leftMargin: -15
}
}
}
}
spacing: 80
}
}
ListModel {
id: myModel
}
/* Fill the model with default values on startup */
Component.onCompleted: {
for (var i = 0; i < 2; i++) {
myModel.append({
name: "Big Animal : " + i
})
}
}
}
I also tried separating the header from ListView into a different component and anchoring the listview below it and that worked. The only problem was it could not be scrolled with the listview. Worst case, I could make a scrolling animation for it but that seems like an inefficient solution and I'd like to know why this doesn't work.
You are probably also biting yourself with the Item as the top-level in the delegate, since that doesn't give any implicit size, which the ListView uses to calculate the scrolling needs. You can simply use Text directly as the delegate (you don't need the Component either) and put the line/rectangle inside. If doing so you can use the contentHeight property of ListView to size the background.
Furthermore, I would suggest to have the ListView as the top level and do any styling secondary, with which I mean, put the background Rectangle inside.
import QtQuick 2.12
import QtQuick.Window 2.12
Window {
width: 640
height: 480
visible: true
title: qsTr("Hello World")
ListView {
id: listView
model: 3
anchors.fill: parent
Rectangle { //background
color: "yellow"
z: -1
width: listView.width
height: listView.contentHeight
}
delegate: Text {
text: "name" + index
color: "black";
font.pixelSize: 50
leftPadding: 20
Rectangle {
height: 1
color: 'black'
width: listView.width
y: - 12
x: -15
}
}
spacing: 80
}
}
Btw, if you are going to put the ListView in some RowLayout or something, you probably also want implicitHeight: contentHeight in the ListView.
The binding loop is originating from the ListView's height: childrenRect.height statement. It looks like the ListView needs to be a fixed height, or at least not dependent on childrenRect. It is most likely how the ListView element knows that the view should be scrollable to view elements below.
It really depends on what you're trying to achieve with setting the height to match childrenRect, but in my case, ListView height is changing based on the children (per your desire presumably). With a 100 items the height came out to be 7970. With 5 items in the model, the result was 350. You can check this by adding a debug or console.log() with onHeightChanged However, as a result of this scaling, the ListView is assumed to be big enough to view the entire data set regardless of the window parent container size.
You do not need to scale the ListView height to match the contents; that is what it is built for. It allows scrolling because the contents are too big to be shown within its limited height.
I was able to achieve get rid of the binding loop and be able to scroll by simply changing the statement to a static value, which is the parent height of 800 as an example:
Window {
visible: true
width: 800
height: 800
Rectangle {
id: listContainer
height: childrenRect.height
width: parent.width
color: "transparent"
anchors {
top: parent.top
topMargin: 30
left: parent.left
leftMargin: 45
}
ListView {
anchors.top: parent.top
anchors.left: parent.left
anchors.right: parent.right
model: myModel
height: 800//childrenRect.height
header:
Text {
z: 2
height: 50
text: "HEADER"
color: "black"
}
delegate: Component {
Item {
Text {
id: userName;
text: name;
color: "black";
font.pixelSize: 50
anchors {
left: parent.left
leftMargin: 20
}
}
Rectangle {
height: 1
color: 'black'
width: listContainer.width
anchors {
left: userName.left
top: userName.top
topMargin: - 12
leftMargin: -15
}
}
}
}
spacing: 80
}
}
ListModel {
id: myModel
}
/* Fill the model with default values on startup */
Component.onCompleted: {
for (var i = 0; i < 100; i++) {
myModel.append({
name: "Big Animal : " + i
})
}
}
}
Edit:
I feel like you're trying to just secure a background for a scalable ListView. Having a static background as a container works but not very well for modern unser interfaces - any bounce effects or such will not move the rectangle. You could achieve this by anchoring the rectangle to the ListView element but it is a very roundabout way. Instead, you could just set a rectangle to style each element of the ListView delegate instead.
delegate: Component {
Item {
Rectangle{
width: listContainer.width
height: userName.height+13
//add 13 to adjust for margin set below
anchors {
left: userName.left
top: userName.top
topMargin: - 12
leftMargin: -15
//just copying from the other rectangle below
}
gradient: Gradient {
//I am just using gradient here for a better understanding of spacing. You could use color.
GradientStop { position: 0.0; color: "aqua" }
GradientStop { position: 1.0; color: "green" }
}
}
Text {
id: userName;
text: name;
color: "black";
font.pixelSize: 50
anchors {
left: parent.left
leftMargin: 20
}
}
Rectangle {
height: 1
color: 'black'
width: listContainer.width
anchors {
left: userName.left
top: userName.top
topMargin: - 12
leftMargin: -15
}
}
}
}
This will make sure that the rectangle background behind the ListView will look like it is scrolling with the items. In reality we have broken one rectangle into multiple and just set each element with one. You can also use this type of styling to achieve alternate colors in your list for example.
I am attempting to make a PDF viewer inside of a Flickable in QML. To do this I use the Poppler library to render my PDFPages to images. When I zoom, I re-scale the size of the image, causing the content Height and Width to change.
My question is, when I zoom out to the point where the image width is less than the Flickable width, the image is shoved to the left. Similarly, if I flip the orientation and the height of the image becomes less than the FlickArea height, the image is locked to the top. Is there any good way to center the image in the FlickArea window?
For the purposes of making this example simpler I replaced my PDF image with a Rectangle.
//Flickable qml snippet
Flickable
{
id: flickArea
anchors.fill: parent
anchors.centerIn: parent
focus: true
contentWidth: testRect.width
contentHeight: testRect.height
clip: true
Rectangle
{
id: testRect
color: "red"
width: 2550 * zoom
height: 3300 * zoom
property double zoom: 1.0;
}
}
//zoom button snippet
Item
{
id: zoomContainer
width: 80
height: zoomColumn.childrenRect.height
z: 2
anchors
{
right: parent.right
bottom: parent.bottom
rightMargin: 10
bottomMargin: 10
}
Column
{
id: zoomColumn
width: parent.width
spacing: 5
anchors
{
right: parent.right
}
Button
{
id: zoomInButton
height: 75
width: parent.width
text: '+'
onClicked: {
testRect.zoom += 0.1
console.log(testRect.zoom)
}
}
Button
{
id: zoomOutButton
height: 75
width: parent.width
text: '-'
onClicked: {
testRect.zoom -= 0.1
console.log(testRect.zoom)
}
}
}
}
Try something like this:
Flickable
{
id: flickArea
anchors.fill: parent
// anchors.centerIn: parent // redundant code
focus: true
contentWidth: wrapper.width
contentHeight: wrapper.height
clip: true
Item
{
id: wrapper
width: Math.max(flickArea.width, testRect.width)
height: Math.max(flickArea.height, testRect.height)
Rectangle
{
id: testRect
color: "red"
anchors.centerIn: parent // centered in wrapper
width: 2550 * zoom
height: 3300 * zoom
property double zoom: 1.0;
}
}
}
Let us suppose I have a card made using Rectangle and I want to show buttons on top of it when clicked. I'm calling showMenu() function to do that and for buttons I'm using an ListView with dynamic ListModel. The problem with such is that the button gets added bellow the Rectangle instead of the top of it. The anchor is not updating after appending an item to the model. Here is my code
Item {
width: 120
height: 120
Rectangle {
id: card
width: 50
height: 100
color: "pink"
anchors.bottom: parent.bottom
Item {
id: rec
width: 50
anchors.bottom: parent.top // This anchor is not updating after appending an item to the list.
ListModel {
id: menuListModel
}
Component {
id: delegate
Rectangle {
width: 120
height: 20
color: "blue"
Text {
anchors.fill: parent
anchors.centerIn: parent
text: commandText
}
}
}
ListView {
anchors.fill: parent
model:menuListModel
delegate: delegate
interactive: false
}
}
MouseArea {
anchors.fill: parent
onClicked: menuListModel.append({"commandText" : "Normal Summon"});
}
}
}
This is more or less a duplicate of this question. The Item needs a height. As mentioned in the answer to that question, you can add debug statements to the code when things like this happen. In this situation, you can also add a Rectangle as a child of the Item and make sure that it's visible:
Rectangle {
anchors.fill: parent
color: "transparent"
border.color: "darkorange"
}
If it's not visible, you know that the problem lies with that (parent) item.
Let's assume I have a component like this:
Rectangle {
id: rec1
Rectangle {
id: rec
x:10;y:100; height:100;
color: 'red'
anchors {
left: parent.left
right: parent.right
}
Loader {
id:loader
width: parent.width
sourceComponent: comp
}
}
Component {
id: comp
Rectangle {
anchors {
left: parent.left
leftMargin: 1 // this line
right: parent.right
}
height:img.height
Image {
id: img
source: '/myimage.png'
width: parent.width
fillMode: Image.PreserveAspectFit
}
}
}
}
the console reports:
QML Image: Binding loop detected for property "width"
But if I change the comp leftMargin to leftMargin: 0 (not 1), everything is ok
Is this a bug or some feature I am missing?
In my opinion you made a typo:
width:100; height:100;
...
anchors {
left: parent.left
right: parent.right
}
By doing this you:
Explicitly set your rectangles width (to 100).
Do explicitly anchoring of left side to parents left side (if this is only one anchoring operation -- it is Ok) and then -- do anchoring of right side to parent's right side (so you are implicitly defining your rectangle's width).
It is contradiction. Try to solve it (for example, by removing right anchoring) and re-run your application.