QML ListView:检测到属性“高度”的绑定循环
Posted
技术标签:
【中文标题】QML ListView:检测到属性“高度”的绑定循环【英文标题】:QML ListView: Binding loop detected for property "height" 【发布时间】:2021-09-20 20:38:19 【问题描述】:我有一个 QML ListView,我正在尝试向它动态添加元素。我希望背景矩形也随着元素从 ListView 添加/删除而动态缩放。现在我得到一个绑定循环,我明白它们是什么,但我不知道它来自哪里。我尝试了一下更改代码,并且有一次能够摆脱绑定循环,但是 ListView 无法滚动。有人有什么想法吗?
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
)
编辑:正如@Aditya 所建议的,绑定循环可以通过具有静态 ListView 高度来删除,但我不希望这样。我使用矩形作为 ListView 的背景,我希望它根据 ListView 进行缩放。例如,如果我只添加两个元素,我希望矩形也针对这两个元素进行缩放,而不是覆盖整个屏幕。这会导致一个问题:
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
)
我还尝试将标题从 ListView 分离到不同的组件中,并将列表视图锚定在它下面,这很有效。唯一的问题是它不能用列表视图滚动。最坏的情况,我可以为它制作一个滚动动画,但这似乎是一个低效的解决方案,我想知道为什么这不起作用。
【问题讨论】:
【参考方案1】:您可能还会将Item
作为代理中的***,因为它没有给出任何隐式大小,ListView
使用它来计算滚动需求。您可以简单地将Text
直接用作代表(您也不需要Component
)并将线条/矩形放入其中。如果这样做,您可以使用ListView
的contentHeight
属性来调整背景大小。
此外,我建议将ListView
作为顶层并进行任何次要样式,我的意思是,将背景Rectangle
放在里面。
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
顺便说一句,如果您要将 ListView 放入 RowLayout
或其他东西中,您可能还希望将 implicitHeight: contentHeight
放入 ListView
中。
【讨论】:
【参考方案2】:绑定循环源自 ListView 的 height: childrenRect.height
语句。看起来 ListView 需要是一个固定的高度,或者至少不依赖于 childrenRect。很可能是 ListView 元素如何知道视图应该可以滚动以查看下面的元素。
这实际上取决于您通过将高度设置为匹配childrenRect
来实现的目标,但在我的情况下,ListView 的高度会根据孩子而变化(大概根据您的意愿)。 100 个项目的高度为 7970。模型中有 5 个项目,结果为 350。您可以通过添加调试或 console.log()
和 onHeightChanged
来检查这一点。但是,由于这种缩放,假定 ListView 足够大,可以查看整个数据集,而不管 window 父容器的大小。
你不需要缩放 ListView 的高度来匹配内容;这就是它的目的。它允许滚动因为内容太大而无法在其有限的高度内显示。
我可以通过简单地将语句更改为静态值来实现摆脱绑定循环并能够滚动,例如父高度为800:
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
)
编辑:
我觉得您只是在尝试为可扩展的 ListView 保护背景。将静态背景作为容器可以工作,但对于现代 unser 界面来说不是很好 - 任何反弹效果等都不会移动矩形。您可以通过将矩形锚定到 ListView 元素来实现这一点,但这是一种非常迂回的方式。相反,您可以设置一个矩形来设置 ListView 委托的每个元素的样式。
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
这将确保 ListView 后面的矩形背景看起来像是随着项目滚动。实际上,我们已经将一个矩形分成多个,并且只为每个元素设置一个。例如,您还可以使用这种样式来实现列表中的替代颜色。
【讨论】:
是的,我也试过了,而且效果很好,只是我使用矩形作为列表的背景,我希望它与列表一起缩放。知道如何在不遇到此绑定循环问题的情况下完成此操作吗? 矩形将留在 ListView 后面,没有任何问题。你在这里面临什么问题?我将矩形的颜色更改为紫色,它按预期保持静态。 例如,假设我只添加了两个元素(最后的 for 循环只运行两次),我只想要这些元素的颜色背景,但现在背景覆盖了整个屏幕,因为它有静态高度。我用一个可以显示问题的示例编辑了问题。 在这种情况下,您需要调整矩形的高度,而不是 ListView。类似于height: list.childrenRect.height
和ListView id: list
。调整边距和间距(您可能需要为此添加静态值)。然而,矩形将是静态的。位置不会根据过度滚动的反弹效果而改变。这需要更多的工作。为什么不改为更改列表元素委托样式?
哦,我认为这行得通。我觉得我试过了,但我可能错过了一些东西。感谢您的帮助!以上是关于QML ListView:检测到属性“高度”的绑定循环的主要内容,如果未能解决你的问题,请参考以下文章
检测到属性宽度的 QML 绑定循环(TextMetrics 行为怪异)