Багги результаты привязок свойства, положение объекта перерывается на вставку

StackOverflow https://stackoverflow.com//questions/21063748

Вопрос

Я создаю дерево объектов, дерево нарисовано с помощью очень простой логики:

    .
  • Каждый объект такой же большой, как его собственное представление плюс, что его дети (и их дети и так далее ...)
  • Если объект является первым ребенком его родителя, это нарисовано с отступом под его визуальное представление
  • каждый следующий объект рисуется непосредственно под его предыдущим братом

Однако этот простой алгоритм не удается при вставке новых объектов в некоторых случаях. Например:

Введите описание изображения здесь

В этом случае узел 1 и 2 успешно вставлены в узел 0, с полной высотой узла 0 (черная линия слева от каждого узла), являющаяся суммой собственного пользовательского интерфейса, а также его дети.

Но когда узел 3 вставлен в узел 1, разрывы макета - узел 2 не нажата вниз, в результате он перекрывается с недавно вставленным узлом, что делает его черную линию невидимой.

Когда запускается дополнительный цикл обновления, дерево возвращается к нормальному, поэтому глюк должен быть причиной некоторыми временными свойствами «или синхронизации». Обратите внимание, что одно дополнительный обновление не всегда помещают дерево в порядке, в зависимости от того, где вставка сделана, ошибка иногда может возникнуть несколько циклов обновления, чтобы «каскад» выключить от нарушения выравнивания.

Любые идеи, что может вызвать это ошибочное поведение и / или как его исправить? Что заставляет код изредка разбиться, и почему, хотя он в конечном итоге работает, требуется, чтобы один для нескольких обновлений, чтобы получить себя в порядке?

Редактировать: Я смог изолировать и точно определить, когда выравниваете разрыв - при вставке в узел, который не заканчивается последним узлом на его уровне. Все привязки распространяются должным образом до тех пор, пока каждый новый узел вставлен в узел, который является последним и «открытым» E.G. На этом уровне нет следующего узла, но вставка в любой предыдущий узел нарушает привязки. Таким образом, дополнительные циклы обновления необходимы для поэтапности ошибки через все уровни, которые он влияет. Но я до сих пор не знаю, что это заставляет и как это исправить, только когда это происходит.

Редактировать: расследование немного больше, кажется, что после того, как новый ребенок вставлен в родительский элемент, и его дети переопределены на основе своего заказа, свойство childrenRect родителя не отражает изменения в размере Отказ Таким образом, когда находится следующий брат объекта, вставленного в вставленные в положение, он по-прежнему использует старое устаревшее значение для высоты объекта, что не влияет на вновь вставленный объект, поскольку он не использует его. Поэтому я предполагаю, что следующий большой вопрос - это то, как это исправить, чтобы привязки имели место, поскольку они должны так, чтобы алгоритм мог работать, как и ожидалось с правильными данными? Я пытался использовать таймер, чтобы задержать операцию, но не кажется, что это проблема времени, но о логическом порядке, например, Количество обновлений в настоящее время требуется устранить ошибку, равную отдаче, она произошла.

Редактировать: я подумал, как «решить это», но ... не совсем, я до сих пор не знаю, что вызывает его и как его избежать, но немного более «экономичное» решение, чем обновление всего дерева до Исправлено, просто понижайте родителей и обновляйте только текущую ветвь до достижения корня. Это очень много экономит, но я все равно предпочел бы иметь правильные значения сразу, поскольку привязки должны работать, по крайней мере, 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, и вставка нигде глубже, ваш первый проход будет вызвать только первое обновление привязки для высоты, поэтому следующий цикл обновления его следующий брат может быть правильно расположен. Если вставка была глубже, было бы больше привязки, которые должны иметь место.

Причина, по которой новый узел вставлен правильно, это не полагается на свойство, которое его собственная вставка не изменится до следующего обновления, которое будет использовать еще не обновленное значение, а затем оценить привязку, чтобы сделать его удар следующий цикл.

Я думаю, что самый быстрый способ сделать это, чтобы начать на уровне вставки и распространять обновление «наружу» и «вниз» E.G. Обновите каждый следующий объект, затем следующие братья и сестер родителей к братьям следующего родителя, пока вы не ударите свой корневой объект. Это будет ли только изменение объектов, которые «под» и затронуты вставкой, которые должны побрить много циклов по сравнению с вашим текущим лучшим решением.

Другие советы

Я немного играл с qml и js, и он настроил, что у меня нет графических пользовательских проблем.

Мой Демо-проект умеет добавлять дочерние объекты, а также братья и сестрыДерево (по левому и правой кнопкой мыши на красных коробках).Логика может не быть полной, но основные основы проходят очень плавно.

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 { }
    }
}
.

Красная коробка и окружающий элемент для размещения братьев и сестер Position.qml

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: component_creation.js

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