我创建一个对象树,树是使用非常简单的逻辑绘制的树:

  • 每个对象都像自己的表达一样大,加上其子女(及他们的孩子等等......)
  • 如果对象是其父级的第一个子项,它将在其视觉表示下缩进
  • 每个下一个对象都直接绘制在其先前的兄弟
但是,在某些情况下插入新对象时,此简单算法将失败。例如:

在这种情况下,节点1和2被成功插入到节点0中,具有节点0的完整高度(每个节点的黑线)是其自己的UI加上其子的总和。

但是当节点3插入节点1时,布局中断 - 节点2不会被按下,结果与新插入的节点重叠,使其黑线是不可见的。

当触发额外的刷新周期时,树返回正常情况,因此故障必须由某些临时“或同步”属性导致。请注意,一个额外的刷新并不总是按顺序排列树,具体取决于插入件的位置,错误可能需要几个刷新周期,以“级联”关闭“扰乱对齐”。

任何可能导致这种不稳定行为和/或如何修复它的想法?是什么导致代码偶尔突破,为什么虽然它最终工作,但它需要一个到多个刷新以便按顺序获得自己?

编辑:对齐中断时,我一直可以隔离和精确定位 - 插入未结束其级别上最后一个节点的节点时。只要每个新节点插入到最后一次和“打开”的节点中,所有绑定都可以正常传播。该级别上没有下一个节点,但在任何先前的节点中插入中断绑定。因此,需要额外的刷新周期来逐步通过所有影响的所有级别逐步淘汰错误。但我仍然不知道是什么导致它以及如何解决它,只有在发生时。

编辑:调查一下,看起来似乎在新子项被插入父项后,它的子项根据其顺序重新对齐,父母的childrenRect属性不会立即反映大小的变化。因此,当插入到的对象的下一个兄弟正在定位时,它仍然使用旧的过时值为对象高度,这不会影响新插入的对象,因为它不会使用它。所以我想下一个大问题是如何解决它,以便如此绑定,因为它们应该这样的算法可以按照正确的数据按预期工作?我尝试使用计时器延迟操作,但它似乎并不是一个问题,但是关于逻辑顺序,例如逻辑顺序。它目前需要的刷新计数来消除它发生的Dept的错误。

编辑:我认为如何“解决它”但是......不是真的,我仍然不知道是什么导致它以及如何避免它,但是比更新整个树更新,直到它更加“经济”解决方案已修复只是沿着父母卸下,只更新当前分支,直到达到root。这确实节省了很多,但我仍然愿意立即拥有正确的值,因为绑定应该工作,至少是IMO。

编辑:以下是订购代码:

for (int i = 0; i < _children.size(); ++i) {
        UI * ui = _children.at(i)->_ui;
        if (ui) {
            if (i) {
                UI * prev = _children.at(i-1)->_ui;
                ui->setX(prev->x());
                ui->setY(prev->height() + prev->y());
            } else {
                ui->setX(Object::_helper->nodeSize());
                ui->setY(_ui->childOffset());
            }
        }
    }
.

和一个示例如何设置QML:

UI {
    id: main
    width: childrenRect.width
    height: childrenRect.height    

    Item { 
        height: childrenRect.height

        Rectangle {
            width: Helper.nodeSize
            height: Helper.nodeSize
            color: "red"

            Text {
                anchors.centerIn: parent
                text: main.id
            }

            MouseArea {
                anchors.fill: parent   
                acceptedButtons: Qt.LeftButton | Qt.RightButton                 
                onClicked: {
                    if (mouse.button == Qt.RightButton)
                        Helper.gotoXY(main.absolutePosition())
                    else {
                        Helper.createObject(1, main)
                        Helper.updateRoot()
                    }
                }

                Rectangle {
                    height: main.height
                    width: 10
                    x: -10
                    color: "black"
                }
            }
        }
    }
}
.

有帮助吗?

解决方案

当你想到它时,这种行为是完美的意义,绑定没有错,只要你对他们所能做的东西的期望。

您的“级联更新”作品的原因非常简单,并指出为什么您的代码不起作用以及如何修复它。

基本上,当您插入新节点时,它将推动“节点”的所有内容,这就是为什么您的代码不打破的原因,只要您插入“最后一个”节点。但如果它不是最后,它将推动一切,但这种变化不会反映,直到其父级更新位置。如果从root呼叫更新并且插入位于任何更深的位置,您的第一个传递将仅触发最初的高度的绑定更新,因此下一个更新周期可以正确定位它的下一个兄弟。如果插入更深,则会有更多的绑定需要进行。

正确插入新节点的原因是它并不依赖于其自己的插入不会改变的属性,直到下次更新将使用仍然不更新的值,然后评估绑定以使其启动下一个循环。

我认为这是最快的方法,它将在插入级别开始,并传播更新“向外”和“向下”。更新每个下一个对象,然后将父父的下一个兄弟姐妹到下一个父级的兄弟姐妹,直到击中根对象。这将只会重新定位在“下面”并受插入的影响,这应该与当前最佳解决方案相比刮掉大量周期。

其他提示

我用qml和js一点点播放,它调整了我没有图形ui问题。

我的演示项目能够添加子对象以及兄弟姐妹一棵树(在红色框上左键并右键单击)。逻辑可能无法完成,但基础运行非常顺利。

main.qml

import QtQuick 2.1
import QtQuick.Controls 1.0

ApplicationWindow {
    id: app
    width: 800
    height: 600

    property int lastNodeId: 0
    function getId() { return lastNodeId++; }

    Level { }
}
.

Level.qml

import QtQuick 2.0

Item {
    id: frame
    width: childrenRect.width
    height: childrenRect.height

    Rectangle {
        width: 10
        color: "#000000"
        height: parent.height
        x: 0
        y: 0
    }

    Column {
        x: 10
        id: content

        Position { }
    }
}
.

红色框和一个周围的项目,以放置兄弟姐妹世代古典etagcode

import QtQuick 2.0
import "component_creation.js" as CC

Item {
    id: position0
    width: childrenRect.width
    height: childrenRect.height

    Rectangle {
        color: "red"
        width: 80
        height: 30

        Text {
            anchors.fill: parent
            horizontalAlignment: Text.AlignHCenter
            verticalAlignment: Text.AlignVCenter

            Component.onCompleted: text = app.getId() // Set once, avoid bindung

            MouseArea {
                anchors.fill: parent
                acceptedButtons: Qt.LeftButton | Qt.RightButton | Qt.MiddleButton
                onClicked: {
                    if (mouse.button == Qt.LeftButton)
                    {
                        CC.createChild(position0);
                    }
                    else if (mouse.button == Qt.RightButton)
                    {
                        CC.createSiblingAfter(position0)
                    }
                    else if (mouse.button == Qt.MiddleButton)
                    {
                        // no clue how to implement
                        // CC.createSiblingBefore(position0)
                    }
                }
            }
        }
    }
}
.

和一些javascript:Position.qml

function createChild(parent_item) {
    var component = Qt.createComponent("Level.qml");
    if (component.status == Component.Ready)
    {
        var sprite = component.createObject(parent_item, {"x": 70, "y": 30});
        if (sprite == null) console.log("Error creating Level object");
    }
    else
    {
        console.log("Error loading component:", component.errorString());
    }
}

function createSiblingAfter(sibling_position)
{
    var component = Qt.createComponent("Position.qml");
    if (component.status == Component.Ready)
    {
        var sprite = component.createObject(sibling_position.parent);
        if (sprite == null) console.log("Error creating Position object");
    }
    else
    {
        console.log("Error loading component:", component.errorString());
    }
}
.

希望有帮助。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top