Los resultados de Buggy de los enlaces de la propiedad, la posición de objeto se rompe en el inserto

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

Pregunta

creo un árbol de objetos, el árbol se dibuja usando lógica muy simple:

  • Cada objeto es tan grande como su propia representación más la de sus hijos (y sus hijos, etc.)
  • Si el objeto es el primer hijo de su padre, se dibuja con sangría bajo su representación visual
  • Cada siguiente objeto se dibuja directamente bajo su hermano anterior

Sin embargo, este simple algoritmo falla al insertar nuevos objetos en algunos casos. Por ejemplo:

ingrese la descripción de la imagen aquí

En este caso, el nodo 1 y 2 se insertan correctamente en el nodo 0, con la altura completa del nodo 0 (la izquierda negra a la izquierda de cada nodo) es la suma de su propia UI más tanto a sus hijos.

Pero cuando el nodo 3 se inserta en el nodo 1, las roturas de diseño: el nodo 2 no se empuja hacia abajo, ya que un resultado se superpone con el nodo recién insertado, lo que hace que su línea negra sea invisible.

Cuando se activa un ciclo de actualización adicional, el árbol vuelve a la normalidad, por lo que la falla debe ser causa por algunas propiedades temporales "o de sincronización". Tenga en cuenta que una actualización adicional no siempre coloca el árbol en orden, dependiendo de dónde se haga el inserto, el error a veces puede tomar algunos ciclos de actualización a "cascada hacia afuera" de alineación de la alineación.

¿Alguna idea de qué podría causar este comportamiento errático y / o cómo solucionarlo? ¿Qué hace que el código se rompa ocasionalmente, y por qué aunque, en última instancia, lo hace, requiere que uno se actualice en múltiples se recupere en orden?

Editar: He podido aislar y modelar cuando se rompe la alineación, cuando se inserta en un nodo que no está terminando con el último nodo en su nivel. Todas las enlaces se propagan correctamente, siempre y cuando cada nodo nuevo se inserta en un nodo que sea el último y "Abrir", por ejemplo. No hay ningún nodo siguiente en ese nivel, pero la inserción en cualquier nodo anterior rompe los enlaces. Por lo tanto, se necesitan ciclos de actualización adicionales para eliminar el error a través de todos los niveles que afecta. Pero todavía no sé qué lo causa y cómo solucionarlo, solo cuando ocurre.

Editar: Investigando un poco más, parece que después de que el nuevo niño se inserta en el elemento principal y sus hijos se reestablecen en función de su pedido, la propiedad GeneracDicEtCode de los padres no refleja los cambios de tamaño de inmediato. . Entonces, cuando se está colocando el siguiente hermano del objeto insertado, aún usa el valor desactualizado anterior para la altura del objeto, que no afecta al objeto recién insertado, ya que no lo usa. Entonces, supongo que la siguiente gran pregunta es cómo solucionarlo para que se realicen los enlaces, ya que deberían que el algoritmo pueda funcionar como se espera con los datos correctos. Intenté usar un temporizador para retrasar la operación, pero no parece que es un tema del tiempo, sino sobre un orden lógico, por ejemplo. El recuento de actualización actualmente requiere eliminar el error igual al departamento que ocurrió.

Editar: Pensé cómo "resolverlo", pero ... en realidad, todavía no sé qué lo causa y cómo evitarlo, pero una pequeña solución más "económica" que actualizar todo el árbol hasta que Se arregla, simplemente vaya a los padres y actualice solo la sucursal actual hasta que se alcance la raíz. Esto ahorra mucho, pero todavía preferiría tener los valores correctos de inmediato, ya que se supone que las enlaces funcionan, al menos imo.

Editar: Aquí está el código de pedido:

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());
            }
        }
    }

y un ejemplo de cómo se configura el 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"
                }
            }
        }
    }
}

¿Fue útil?

Solución

Cuando lo piensas, ese comportamiento tiene perfecto sentido, no hay nada de malo en los enlaces, solo con sus expectativas de lo que son capaces.

La razón por la que las obras de "actualización de cascada" es muy sencilla y señala por qué su código no funciona y cómo solucionarlo.

Básicamente, cuando inserta un nuevo nodo, lo empuja todo hacia abajo "un nodo", por lo que su código no se rompe siempre y cuando inserte un nodo "Último". Pero si no está al final, empujará todo un poco, pero este cambio no se reflejará hasta que su padre actualice las posiciones. Si llama a la actualización de la raíz y el inserto es más profundo, su primera pasada activará solo la primera actualización del enlace para la altura, por lo que el próximo ciclo de actualización su próximo hermano se puede colocar correctamente. Si el inserto fue más profundo, habría más enlaces que deban tener lugar.

La razón por la que se inserta correctamente el nuevo nodo es que no se basa en la propiedad que su propia inserción no cambiará hasta la próxima actualización que use el valor aún no actualizado y luego evalúe la unión para que se inicie. el siguiente ciclo.

Creo que la forma más rápida de hacerlo será comenzar a partir del nivel del inserto y propagar la actualización "hacia afuera" y "hacia abajo", por ejemplo. Actualice cada siguiente objeto, luego los siguientes hermanos del padre a los hermanos de los siguientes padres hasta que llegue a su objeto raíz. Esto solo reposicionará los objetos que están "bajo" y afectados por el inserto, que deben afeitarse muchos ciclos en comparación con su mejor solución actual.

Otros consejos

Toqué con QML y JS un poco y afirmó que no tengo problemas gráficos de UI.

My Proyecto de demostración es capaz de agregar objetos infantiles, así como a hermanos aUn árbol (por clic izquierdo y derecho en las cajas rojas).Es posible que la lógica no esté completa, pero los conceptos básicos se ejecutan de manera muy suave.

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

La caja roja y un elemento circundante para colocar hermanos 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)
                    }
                }
            }
        }
    }
}

y algunos 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());
    }
}

espero que ayude.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top