首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >QML列:可能的QQuickItem::polish()循环

QML列:可能的QQuickItem::polish()循环
EN

Stack Overflow用户
提问于 2021-02-21 23:12:36
回答 3查看 921关注 0票数 1

下面的代码有两个问题。

如果我在QML列中使用padding,我会收到以下消息:

QML列:可能的QQuickItem::polish()循环

并且应用程序变得无响应。另外,如果我不使用锚点,问题就不会出现,但列中的矩形不会被拉伸。

如果我使用锚点,列的implicitWidth和impliciHeight将为零,这将导致矩形不会显示。

Qt文档是这样写的:

此外,由于列自动垂直定位其子项,因此列中的子项不应设置其y位置,也不应使用top、bottom、anchors.verticalCenter、fill或centerIn锚点垂直锚定自身。

这意味着水平锚定(左/右)不被禁止。

你知道会出什么问题吗?

代码语言:javascript
运行
复制
Rectangle {
    anchors.fill: parent
    color: "green"
    Rectangle {
        anchors.centerIn: parent
        implicitWidth: col.implicitWidth
        implicitHeight: col.implicitHeight
        color: "blue"
        Column {
            spacing: 10
            //padding: 10 // causes: QML Column: possible QQuickItem::polish() loop
            id: col
            Rectangle {
                anchors.left: parent.left
                anchors.right: parent.right
                implicitWidth: 100
                implicitHeight: 25
            }
            Rectangle {
                //anchors.left: parent.left // uncommenting these anchors will result that the column's implicitWidth and implicitHeight will be 0
                //anchors.right: parent.right
                implicitWidth: 200
                implicitHeight: 25
            }
            Component.onCompleted: console.log("column, imp width: " + implicitWidth + ", imp height: " + implicitHeight)
        }
    }
}
EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2021-02-28 05:14:36

正如评论中所讨论的,

的代码可以改进:

删除父子关系,改为创建一个新的默认属性别名,如下所示:

代码语言:javascript
运行
复制
Rectangle 
{ 
   default property alias data2: col.data

   data: 
   [ 
      Column 
      { 
        id: col; 
        onChildrenChanged: { ...calculate sizes, add bindings, etc... }
      } 
   ]
}

它是如何工作的:

在QML代码中将对象嵌套在另一个对象中时,是将它们添加到标记为

父对象内部

对于

因此

名为

标记为

该属性包含可视化子级和资源的组合列表。

/

因此,通常将可视元素嵌套在

导致它们被添加为

的视觉子对象

所以通常

..。

...is相当于:

我通过创建一个名为

并将其设置为

对于

因此它的元素不会被添加到

的可视化子项列表

取而代之的是我做了

的别名

属性

一个

属性只是属性的别名,在本例中是属性的另一个名称,作为另一个对象的属性,但这两个名称都“指向”相同的实际属性,因此

的可视化子项列表

所以所有QML元素都嵌套在

被添加为

但是,现在我有一个问题:我不能仅仅嵌套

变成

QML代码,因为这意味着

需要添加为它自己的子项(这没有任何意义)

所以我必须分配

的实际

属性(它不再是默认的,所以我必须显式地写出它的名称),因此添加了

作为

现在,无论何时

的嵌套元素被添加或移除(包括通过

)、

%s

属性的更改,但由于我们添加的是可视子级

属性也会发生更改。

因此,我们可以在以下情况下触发重新计算和重新绑定

%s

信号触发(或

如果您还想在非可视子对象上触发(也称为

)

您可以跳过已具有绑定的元素,也可以仅重新绑定它们

据我所知,这应该是有效的和受支持的QML语法-只是不是您通常使用的语法-所以在生产代码中使用它是可以的,可能会有一个注释来解释正在发生的事情

票数 1
EN

Stack Overflow用户

发布于 2021-02-23 07:40:37

填充

将元素附加到列的左边缘和右边缘,然后告诉列应该将其元素放置在距该边界10个像素的位置。

然后,它们开始通过各自导致布局更新并触发彼此来“打架”。

您需要放置一个中间元素来处理填充,如下所示:

代码语言:javascript
运行
复制
Column{ padding: 10; Column{ id: col; Rectangle{}; Rectangle{}; } }

让我们来看看到底发生了什么

我在每个元素中插入了一些调试代码:

代码语言:javascript
运行
复制
property string name: "..."//I named them: "green_rect", "blue_rect", "col", "top_rect", "bottom_rect"
onWidthChanged: console.log(name + " changed: w=" + width)
....
property string mydbgstr: "top_rect w=" + width + " h=" + height + " iw=" + implicitWidth + " ih=" + implicitHeight
onMydbgstrChanged: console.log(mydbgstr)

当任何属性发生更改时,它都会打印一个字符串

我的窗口是500x500

初始布局-这对于所有情况都保持不变:

代码语言:javascript
运行
复制
// property change notifications removed since they are not interesting yet
qml: bottom_rect w=200 h=25 iw=200 ih=25
qml: top_rect w=100 h=25 iw=100 ih=25
qml: col w=0 h=0 iw=0 ih=0
qml: blue_rect w=0 h=0 iw=0 ih=0
qml: green_rect w=0 h=0 iw=0 ih=0

好了,锚点还没有被应用,列也还没有计算出它的大小,所以元素只是简单地假设h=ih w=iw

在那之后,我们看到了不同的结论:

顶部和底部矩形的锚点都评论道:

代码语言:javascript
运行
复制
qml: col changed: w=200
qml: col changed: h=60 
qml: col changed: iw=200
qml: blue_rect changed: w=200
qml: blue_rect changed: iw=200
qml: blue_rect w=200 h=0 iw=200 ih=0

qml: col changed: ih=60
qml: col w=200 h=60 iw=200 ih=60
qml: blue_rect changed: h=60
qml: blue_rect changed: ih=60
qml: blue_rect w=200 h=60 iw=200 ih=60

qml: green_rect changed: w=500
qml: green_rect w=500 h=500 iw=0 ih=0
qml: green_rect changed: h=500

结果:

代码语言:javascript
运行
复制
▀▀▀▀▀
▀▀▀▀▀▀▀▀▀▀

按照预期工作:列根据组合子元素的大小计算其大小,然后周围的元素也假定该大小

只有top rect的锚点没有注释:

代码语言:javascript
运行
复制
// it appears that top rect adjusted itself to fit still-zero-width column
qml: top_rect changed: w=0   col.w=0 //uh oh, top_rect is now zero-sized
qml: top_rect w=0 h=25 iw=100 ih=25

// here col probably performed layout and determined its width based on bottom rect
// however for some reason its own signal got delayed (isn't shown)
// probably because children get priority

// top_rect anchors react to column layout:
qml: top_rect changed: w=200   col.w=200  //top_rect is properly sized again
qml: top_rect w=200 h=25 iw=100 ih=25

// here col appears to react to the first layout change: 
qml: col changed: w=200
qml: col changed: h=25 // height excludes top_rect which was zero-size at that point
qml: col changed: iw=200 // bottom_rect retained its size so col isn't zero-sized 

//...and so surrounding elements are updated
qml: blue_rect changed: w=200
qml: blue_rect changed: iw=200
qml: blue_rect w=200 h=0 iw=200 ih=0

//...next col decides to update its implicitHeight 
qml: col changed: ih=25
qml: col w=200 h=25 iw=200 ih=25
//...which causes a second layout of surroundings:
qml: blue_rect changed: h=25
qml: blue_rect changed: ih=25
qml: blue_rect w=200 h=25 iw=200 ih=25

qml: green_rect changed: w=500
qml: green_rect changed: h=500
qml: green_rect w=500 h=500 iw=0 ih=0

//This is apparently col getting the second update of top_rect:
qml: col changed: h=60 //height now includes non-zero-sized top_rect
qml: col changed: ih=60
qml: col w=200 h=60 iw=200 ih=60

//...so blue_rect is changed yet again:
qml: blue_rect changed: h=60
qml: blue_rect changed: ih=60
qml: blue_rect w=200 h=60 iw=200 ih=60

结果:

代码语言:javascript
运行
复制
▀▀▀▀▀▀▀▀▀▀
▀▀▀▀▀▀▀▀▀▀

两者均未注释:

代码语言:javascript
运行
复制
// col is zero-sized still so children cling to its zero-size
qml: bottom_rect changed: w=0   col.w=0
qml: bottom_rect w=0 h=26 iw=200 ih=26
qml: top_rect changed: w=0   col.w=0
qml: top_rect w=0 h=24 iw=100 ih=24

// because all children are zero-sized, col is also zero-sized so it doesn't attempt to do anything

// because col is zero-sized, blue_rect also remains zero-sized

qml: green_rect changed: w=500
qml: green_rect changed: h=500
qml: green_rect w=500 h=500 iw=0 ih=0

结果:绿色窗口

结论

列的宽度取决于最大的元素宽度,但是元素的宽度被锚定到列,所以它有一个鸡和蛋的问题,但是因为它是间接的,并且还会导致初始零大小持续存在,Qt无法检测到绑定循环,而是元素保持折叠。

这实际上意味着,在这种情况下,QtQuick还不够“聪明”,不能正确地定位项目。您必须指定其中一项或列的实际宽度。

更聪明一点,因为它可以指定最小、最大和首选大小,所以您可能应该使用它而不是

..。我知道你已经知道如何使用它了,所以我不会在这里详述了。

或者,命令式代码可以用来确定元素的最大宽度,并将col的宽度设置为最大宽度。如果需要,它还可以设置其他元素的宽度。

票数 1
EN

Stack Overflow用户

发布于 2021-02-24 00:04:23

QML列更像是一个定位器,在我的例子中,它不太适合调整其子元素的大小。

我试用了ColumnLayout,它在一定程度上解决了这个问题,但生成了很多警告消息,因为ColumnLayout不是直接的,而是从QQuickLayout派生的,其中检查锚定并转储此警告消息:“在由布局管理的项上检测到锚点。这是未定义的行为;请改用Layout.alignment。”

最后,我在QML中做了一个变通方法,它利用implicitHeight大于零的元素之间的均匀填充和间距。

它可以用作常规的QML元素。

这是根据杰克·怀特的建议修改的答案。

代码语言:javascript
运行
复制
MyColumn.qml:

import QtQuick 2.12

Rectangle
{
    default property alias data2: container.data

    property int spacing: 0
    property int padding: 0

    implicitWidth: container.implicitWidth + 2*padding
    implicitHeight: container.implicitHeight + 2*padding

    data:
    [
        Item
        {
            id: container

            property int spacing: parent.spacing

            function implicitHeightOfChildren() {
                var total = 0
                for (var i=0;i max)
                        max = children[i].implicitWidth
                return max
            }

            function calculateSpacing() {
                var itemsWithHeight = 0
                for (var i = 0; i < children.length; i++)
                    if(children[i].implicitHeight > 0)
                        itemsWithHeight++
                return (itemsWithHeight > 0 ? (itemsWithHeight - 1) * spacing : 0)
            }

            anchors.top: parent.top
            anchors.topMargin: parent.padding
            anchors.left: parent.left
            anchors.leftMargin: parent.padding
            anchors.right: parent.right
            anchors.rightMargin: parent.padding

            implicitWidth: widestChild()
            implicitHeight: implicitHeightOfChildren() + calculateSpacing()

            onChildrenChanged:
            {
                for (var i=0;i 0 ? spacing : 0);
                    }
                }
            }
        }
    ]
}

没有锚定到列的示例使用。取消对锚线的注释以查看预期行为。

代码语言:javascript
运行
复制
MyColumn {
    color: "red"
    padding: 10
    spacing: 10
    Repeater {
        model: 3
        Rectangle {
            //anchors.left: parent.left
            //anchors.right: parent.right
            implicitWidth: 100 + 25 * index
            implicitHeight: 25
            color: "black"
        }
    }
}

结果:

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/66303743

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档