簡體   English   中英

如何分析“綁定循環”

[英]How to analyse a “Binding loop”

我有一個帶有 C++ 模型和 QML 可視化的 Qt/QML 應用程序。

在運行時(啟動),我收到警告

QML 項目:檢測到屬性“xyz”的綁定循環

我在 QML 中沒有看到明顯的循環。 我可以啟用更多調試以了解此循環的來源嗎? 其他建議?

我通常通過在打印警告的 Qt 代碼中放置一個斷點來做到這一點。 為此,您需要有一個帶有調試符號的 Qt。

在 Qt 源中搜索“檢測到綁定循環”給了我QQmlAbstractBinding::printBindingLoopError() 在那里放置斷點通常會導致回溯,從而清楚地了解情況。

更新:David Edmundson 開發了一個小工具,可以在綁定循環上顯示僅限 QML 的回溯,請在此處查看他的博客 引擎蓋下的功能與此處描述的完全相同,只是它很好地自動化並封裝在 Python 腳本中。

示例:

Rectangle {
    id: parent
    width: child.width + 1
    height: child.height + 1
    Rectangle {
        id: child
        anchors.fill: parent
    }
}

回溯:

1   QQmlAbstractBinding::printBindingLoopError  qqmlabstractbinding.cpp 178 0x7ffff6eb36da  
2   QQmlBinding::update qqmlbinding.cpp 221 0x7ffff6eb9abe  
3   QQmlBinding::update qqmlbinding_p.h 97  0x7ffff6eba354  
4   QQmlBinding::expressionChanged  qqmlbinding.cpp 260 0x7ffff6eb9e68  
5   QQmlJavaScriptExpressionGuard_callback  qqmljavascriptexpression.cpp    361 0x7ffff6eb223e  
6   QQmlNotifier::emitNotify    qqmlnotifier.cpp    94  0x7ffff6e9087a  
7   QQmlData::signalEmitted qqmlengine.cpp  763 0x7ffff6e19a45  
8   QMetaObject::activate   qobject.cpp 3599    0x7ffff683655e  
9   QMetaObject::activate   qobject.cpp 3578    0x7ffff6836364  
10  QQuickItem::widthChanged    moc_qquickitem.cpp  1104    0x7ffff7a7ba49  
11  QQuickItem::geometryChanged qquickitem.cpp  3533    0x7ffff7a6e9cd  
12  QQuickItem::setSize qquickitem.cpp  6389    0x7ffff7a75f35  
13  QQuickAnchorsPrivate::setItemSize   qquickanchors.cpp   400 0x7ffff7a60d94  
14  QQuickAnchorsPrivate::fillChanged   qquickanchors.cpp   177 0x7ffff7a5fe0e  
15  QQuickAnchorsPrivate::itemGeometryChanged   qquickanchors.cpp   441 0x7ffff7a6106f  
16  QQuickItem::geometryChanged qquickitem.cpp  3523    0x7ffff7a6e96c  
17  QQuickItem::setWidth    qquickitem.cpp  6091    0x7ffff7a74c1d  
18  QQuickItem::qt_static_metacall  moc_qquickitem.cpp  874 0x7ffff7a7b0dc  
19  QQuickItem::qt_metacall moc_qquickitem.cpp  946 0x7ffff7a7b4d8  
20  QQuickRectangle::qt_metacall    moc_qquickrectangle_p.cpp   610 0x7ffff7c189c2  
21  QMetaObject::metacall   qmetaobject.cpp 296 0x7ffff680118b  
22  QQmlPropertyPrivate::writeBinding   qqmlproperty.cpp    1512    0x7ffff6e33ec3  
23  QQmlBinding::update qqmlbinding.cpp 199 0x7ffff6eb992a  
24  QQmlBinding::update qqmlbinding_p.h 97  0x7ffff6eba354  
25  QQmlBinding::expressionChanged  qqmlbinding.cpp 260 0x7ffff6eb9e68  
26  QQmlJavaScriptExpressionGuard_callback  qqmljavascriptexpression.cpp    361 0x7ffff6eb223e  
27  QQmlNotifier::emitNotify    qqmlnotifier.cpp    94  0x7ffff6e9087a  
28  QQmlData::signalEmitted qqmlengine.cpp  763 0x7ffff6e19a45  
29  QMetaObject::activate   qobject.cpp 3599    0x7ffff683655e  
30  QMetaObject::activate   qobject.cpp 3578    0x7ffff6836364  
31  QQuickItem::widthChanged    moc_qquickitem.cpp  1104    0x7ffff7a7ba49  
32  QQuickItem::geometryChanged qquickitem.cpp  3533    0x7ffff7a6e9cd  
33  QQuickItem::setSize qquickitem.cpp  6389    0x7ffff7a75f35  
34  QQuickAnchorsPrivate::setItemSize   qquickanchors.cpp   400 0x7ffff7a60d94  
35  QQuickAnchorsPrivate::fillChanged   qquickanchors.cpp   177 0x7ffff7a5fe0e  
36  QQuickAnchorsPrivate::update    qquickanchors.cpp   431 0x7ffff7a60fc6  
37  QQuickAnchorsPrivate::updateOnComplete  qquickanchors.cpp   425 0x7ffff7a60f93  
38  QQuickItem::componentComplete   qquickitem.cpp  4593    0x7ffff7a70944  
39  QQmlObjectCreator::finalize qqmlobjectcreator.cpp   1207    0x7ffff6ecab66  
40  QQmlComponentPrivate::complete  qqmlcomponent.cpp   928 0x7ffff6e38609  
41  QQmlComponentPrivate::completeCreate    qqmlcomponent.cpp   964 0x7ffff6e386ee  
42  QQmlComponent::completeCreate   qqmlcomponent.cpp   957 0x7ffff6e386a0  
43  QQmlComponent::create   qqmlcomponent.cpp   791 0x7ffff6e37edd  
44  QQuickView::continueExecute qquickview.cpp  476 0x7ffff7b720d4  
45  QQuickViewPrivate::execute  qquickview.cpp  124 0x7ffff7b7101f  
46  QQuickView::setSource   qquickview.cpp  253 0x7ffff7b71426  
47  main    main.cpp    24  0x4033e4    

在回溯中,可以看到在加載文件時計算了子項的anchors.fill錨點(第 35、36 幀)。 這會導致子項的寬度發生變化(第 31 幀),從而導致對父項上“寬度”屬性(第 17 幀)的綁定進行綁定更新(第 25 幀)。 這反過來又會強制重新計算子錨點(第 14 幀),這會更改子錨點的寬度(第 10 幀),從而更新綁定(第 4 幀)。 這與已在第 25 幀中更新的綁定相同,因此存在綁定循環。 可以看到第25幀和第4幀的this指針是一樣的,即遞歸更新同一個綁定。

非常感謝您的收據,但它對我沒有幫助。 如果有人需要它,請添加另一個可能的解決方案。 我在ListView得到綁定循環,試圖將所有項目寬度和列表寬度設置為項目最大值:

ListView {
    implicitWidth: contentItem.childrenRect.width
    delegate: listItem
}

Item {
    id: listItem
    width: Math.max(internalWidth, listView.implicitWidth)
}

綁定循環錯誤出現在項目計數更新上,但不是每次都出現 - 僅在某些批量綁定更新上出現,而沒有實際的綁定循環。 能夠通過將綁定表達式移動到綁定 QML 類型並向其添加delayed屬性來解決該問題:

Item { // Item causing binding loop
    Binding on item_property_causing_loop {
        value: <binding_expression>
        when: <when_expression> // Optional however could also help
        delayed: true  // Prevent intermediary values from being assigned
    }
}

所以在我的情況下是:

Item { // Item causing binding loop
    id: listItem
    Binding on width {
        value: Math.max(internalWidth, listView.implicitWidth)
        when: index >= 0 // Optional however could also help
        delayed: true    // Prevent intermediary values from being assigned
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM