Domanda

Creo un albero di oggetti, l'albero è disegnato utilizzando la logica molto semplice:

    .
  • Ogni oggetto è grande come la sua rappresentazione più quella dei suoi figli (e dei loro figli e così via ...)
  • Se l'oggetto è il primo figlio del suo genitore è disegnato rientrato sotto la sua rappresentazione visiva
  • Ogni oggetto successivo viene disegnato direttamente sotto il suo fratello precedente

Tuttavia, questo semplice algoritmo fallisce durante l'inserimento di nuovi oggetti in alcuni casi. Ad esempio:

Inserisci Descrizione dell'immagine qui

In questo caso, il nodo 1 e 2 sono inseriti correttamente nel nodo 0, con l'altezza completa del nodo 0 (la linea nera a sinistra di ogni nodo) è la somma del proprio interfaccia utente più sia dei suoi figli.

Ma quando il nodo 3 è inserito nel nodo 1, la disposizione di layout - il nodo 2 non viene spinto verso il basso, come risultato si sovrappone al nodo appena inserito, rendendo la sua linea nera invisibile.

Quando viene attivato un ulteriore ciclo di aggiornamento, l'albero ritorna alla normalità, quindi il problema tecnico deve essere causato da alcune proprietà temporanee "o di sincronizzazione". Si noti che un aggiornamento extra non ha sempre messo l'albero in ordine, a seconda di dove viene effettuato l'inserto, il bug può talvolta assumere alcuni cicli di aggiornamento in "cascata fuori" da disturbare l'allineamento.

Qualche idea ciò che potrebbe causare questo comportamento irregolare e / o come risolverlo? Ciò che causa occasionalmente il codice, e perché anche se alla fine funziona, richiede uno a più rinfrescamenti per arrivarsi in ordine?

Modifica: sono stato in grado di isolare e individuare quando è la rottura dell'allineamento - quando si inserisce in un nodo che non finisce sull'ultimo nodo sul suo livello. Tutti i Bindings si propagano correttamente finché ogni nuovo nodo è inserito in un nodo che dura e "Apri" E.G. Non esiste un nodo successivo su quel livello, ma l'inserimento in qualsiasi nodo precedente rompe i binding. Quindi altri cicli di aggiornamento sono necessari per sfartire il bug attraverso tutti i livelli che colpisce. Ma ancora non so cosa lo causa e come risolverlo, solo quando si verifica.

Modifica: indagarsi un po 'di più, sembra che dopo che il nuovo figlio sia inserito nell'elemento genitore e i suoi figli sono ri-allineati in base al loro ordine, la proprietà childrenRect del genitore non riflette subito le modifiche di dimensioni . Quindi, quando il prossimo fratello dell'oggetto inserito viene posizionato, utilizza ancora il vecchio valore obsoleto per l'altezza dell'oggetto, che non influisce sull'oggetto appena inserito poiché non lo usa. Quindi immagino che la prossima grande domanda sia come risolverlo in modo che tali attacchi avvengano in quanto dovrebbero in modo che l'algoritmo possa funzionare come previsto con i dati giusti? Ho provato a utilizzare un timer per ritardare l'operazione, ma non sembra che sia un problema del tempo ma di un ordine logico, ad es. Il conteggio di Aggiorna attualmente richiede di eliminare il bug uguale al dept che si è verificato a.

Modifica: ho pensato come "risolverlo", ma ... non proprio, non so ancora cosa lo causa e come evitarlo, ma una soluzione più "economica" che aggiorna l'intero albero è fissato basta andare giù i genitori e aggiornare solo il ramo corrente fino a quando viene raggiunta la radice. Questo salva molto, ma preferirei comunque avere i valori giusti subito, poiché le associazioni dovrebbero funzionare, almeno imo.

Modifica: Ecco il codice di ordinazione:

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

E un esempio come è impostato il 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"
                }
            }
        }
    }
}
.

È stato utile?

Soluzione

Quando ci pensi, quel comportamento ha perfettamente senso, non c'è niente di sbagliato nei Binding, solo con le tue aspettative di ciò che sono capaci di.

Il motivo per cui il tuo "aggiornamento a cascata" funziona è molto semplice e indica il motivo per cui il tuo codice non funziona e come risolverlo.

Fondamentalmente, quando si inserisce un nuovo nodo, spinge tutto in basso "un nodo", motivo per cui il tuo codice non si rompe fino a quando inserisci un nodo "ultimo". Ma se non è alla fine, spingerà tutto un po ', ma questa modifica non rifletterà finché il suo genitore aggiorna le posizioni. Se si chiama l'aggiornamento dalla radice e l'inserto è ovunque in profondità, il primo passaggio attiverà solo il primo aggiornamento del legame per l'altezza, quindi il prossimo ciclo di aggiornamento è possibile posizionare correttamente il prossimo fratello. Se l'inserto era più profondo, ci sarebbero più attacchi che devono avvenire.

Il motivo per cui il nuovo nodo viene inserito correttamente è che non si basa sulla proprietà che il proprio inserimento non cambierà fino al successivo aggiornamento che utilizzerà il valore ancora non aggiornato e valuterà il legame per farlo calciare il prossimo ciclo.

Penso che il modo più veloce per farlo sarà quello di iniziare a livello di inserto e propagare l'aggiornamento "verso l'esterno" e "verso il basso" ad es. Aggiorna ogni oggetto successivo, quindi i fratelli successivi del genitore ai fratelli dei genitori successivi fino a quando non si colpisce il tuo oggetto root. Ciò riposizionerà solo gli oggetti "sotto" e influenzati dall'inserto, che dovrebbero raderti un sacco di cicli rispetto alla soluzione più attuale migliore.

Altri suggerimenti

Ho giocato con QML e JS un po 'e si è sintonizzato che non ho problemi di ui grafico.

my Project demo è in grado di aggiungere oggetti figlio e fratelli aUn albero (con clic sinistro e destro sulle scatole rosse).La logica potrebbe non essere completa ma le basi funzionano molto agevolmente.

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 scatola rossa e un oggetto circostante da posizionare i fratelli 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)
                    }
                }
            }
        }
    }
}
.

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

Spero che ti aiuti.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top