Los resultados de Buggy de los enlaces de la propiedad, la posición de objeto se rompe en el inserto
-
26-12-2019 - |
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:
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"
}
}
}
}
}
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.