2014-01-11 6 views
1

개체의 위치를 ​​바꿈 나는 객체의 트리를 생성, 나무는 아주 간단한 논리를 사용하여 그려진 :버기 결과, 삽입

  • 각 개체는 자신의 표현처럼 큰 플러스 아이의 (등 자녀와 ...)
  • 는 개체마다 다음 개체가 이전 형제의 바로 아래에 그려진
  • 그것의 시각적 표현에서 들여 그려 부모의 첫 번째 자식 인 경우

그러나이 간단한 알고리즘은 새로운 개체를 삽입 할 때 실패합니다. 예를 들어

이때

enter image description here

는, 노드 1 및 2가 성공적으로 자신의 UI의 합인 노드 0 (모든 노드의 좌측 검은 선)의 전체 높이와 노드 0에 삽입 그리고 그 두 자녀 모두.

노드 3을 노드 1에 삽입하면 레이아웃이 끊어집니다 - 노드 2는 아래로 밀리지 않습니다. 결과적으로 새로 삽입 된 노드와 겹치기 때문에 검은 선이 보이지 않습니다.

새로 고침주기가 트리거되면 트리가 정상 상태로 돌아가므로 일부 임시 "또는 동기화"속성으로 인해 글리치가 발생해야합니다. 하나의 추가 새로 고침이 트리를 순서대로 배치하지는 않습니다. 삽입 위치에 따라 버그가 때때로 리프레시 사이클을 거쳐 정렬을 방해하지 못하도록 "캐스케이드 아웃"됩니다.

이 비정상적인 동작 및/또는 해결 방법은 무엇입니까? 코드가 가끔씩 중단되는 이유는 무엇이며 궁극적으로 작동하더라도 순차적으로 실행 되려면 여러 번 새로 고침해야합니다.

편집 : 레벨에서 마지막 노드로 끝나지 않는 노드에 삽입 할 때 정렬이 중단되는 시점을 찾아 내고 찾아 낼 수있었습니다. 모든 새로운 바인딩이 마지막이고 "열린"노드에 삽입되는 한 모든 바인딩은 올바르게 전달됩니다. 해당 레벨에는 다음 노드가 없지만 이전 노드에 삽입하면 바인딩이 중단됩니다. 따라서 버그가 영향을 미치는 모든 레벨을 통해 버그를 단계적으로 제거하려면 추가 새로 고침주기가 필요합니다. 그러나 나는 그것이 발생했을 때만 그것을 일으키는 원인과 그것을 고치는 방법을 아직도 모른다.

EDIT : 좀 더 자세히 살펴보면 새 항목을 부모 항목에 삽입하고 해당 항목의 순서에 따라 해당 항목을 다시 정렬 한 후 부모 항목의 childrenRect 속성이 오른쪽의 크기 변경 내용을 반영하지 않는 것으로 보입니다. 떨어져. 따라서 삽입 된 객체의 다음 형제가 배치 될 때 객체 높이에 대해 오래된 오래된 값을 사용합니다. 객체 높이를 사용하지 않으므로 새로 삽입 된 객체에 영향을 미치지 않습니다. 그래서 다음 큰 질문은 올바른 데이터로 알고리즘이 예상대로 작동 할 수 있도록 바인딩을 수행하도록 수정하는 것입니다. 타이머를 사용하여 작업을 지연 시키려고했지만 시간 문제는 아니지만 논리적 순서와 관련되어있는 것으로 보입니다. 그것이 발생한 부서와 동일한 버그를 제거하기 위해 현재 필요한 새로 고침 횟수.

EDIT : "해결 방법"을 알았지 만, 실제로는 그 원인과 회피 방법을 알 수 없지만 전체 트리를 업데이트하는 것보다 "경제적 인"해결책이 될 때까지 부모에게 내려 가서 root에 도달 할 때까지 현재 브랜치 만 업데이트하면됩니다. 이것은 많이 저장하지 않지만 바인딩이 작동하기 때문에 올바른 값을 가지고있는 것을 선호합니다. 최소한 IMO 이상입니다.

편집은 다음 QML 설정 방법

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

그리고 예 : 당신이 그것에 대해 생각할 때, 그 행동이 완벽한 의미가

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" 
       } 
      } 
     } 
    } 
} 
+0

나는 문제와 관련된 코드와 목업이 천 단어의 가치가 있다고 생각한다. :) – lpapp

+0

@ LaszloPapp - 질문을 약간 업데이트했습니다. 두 문제와 일부 코드가 추가되었습니다. –

+0

QML 코드를 더 추가 할 수 있습니까? 예를 들어, id가'childrenRect' 인 요소. –

답변

1

,이 다음 순서 코드 바인딩에 문제가없는 것은 아닙니다.

"계단식 업데이트"가 작동하는 이유는 매우 간단하며 코드가 작동하지 않는 이유와 해결 방법을 지적합니다.

기본적으로 새 노드를 삽입하면 모든 것이 "노드"아래로 푸시되므로 "마지막"노드를 삽입하는 동안 코드가 손상되지 않습니다. 그러나 그것이 끝이 아니라면, 모든 것을 조금씩 밀어 붙일 것이지만,이 변화는 부모가 위치를 업데이트 할 때까지 반영되지 않을 것입니다. 루트에서 업데이트를 호출하고 삽입이 더 깊은 곳이면 첫 번째 패스는 높이에 대한 바인딩의 첫 번째 업데이트 만 트리거하므로 다음 업데이트주기가 다음 번 형제가 올바르게 배치 될 수 있습니다. 인서트가 깊어지면 더 많은 바인딩이 필요합니다.

새 노드를 올바르게 삽입 한 이유는 다음 업데이트까지는 자체 삽입이 변경되지 않는 속성에 의존하지 않으므로 여전히 업데이트되지 않은 값을 사용하고 바인딩을 평가하여 킥하게 만듭니다. 다음주기에

이 작업을 수행하는 가장 빠른 방법은 삽입 수준에서 시작하여 "바깥 쪽"및 "아래쪽"업데이트를 전파하는 것입니다. 모든 다음 객체를 업데이트 한 다음 루트 객체를 칠 때까지 부모의 다음 형제를 다음 부모의 형제에게 업데이트합니다. 이렇게하면 "아래"인 개체의 위치가 변경되고 삽입물의 영향을 받아 현재 최상의 솔루션과 비교하여 많은 사이클을 줄일 수 있습니다.

0

나는 QML과 JS로 약간 놀았고 그래픽 UI 문제가 없다고 조정했다.

demo project은 (빨간색 상자의 왼쪽 및 오른쪽 클릭으로) 형제뿐만 아니라 형제도 하위 개체에 추가 할 수 있습니다. 논리가 완벽하지는 않지만 기본이 매우 원활하게 실행됩니다.

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

빨간색 상자와 주변의 항목을 배치 할 형제 자매

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

Position.qml 그리고 어떤 자바 스크립트 : 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()); 
    } 
} 

희망이 있습니다.

+0

모든 코드가 이벤트 기반 QML이므로 모든 변경 사항이 즉시 반영되므로 C++을 사용하여 이벤트 루프를 인터럽트하므로 바인딩이 지연으로 업데이트됩니다. – dtech

+0

Jap, 바인딩을 최대한 활용하여 "새로 고침"기능이 필요하지 않습니다. 상자가 생성 될 때까지 모든 부모 및 형제 상자는 필요에 따라 조정됩니다. QML 객체를 만드는 것이 Javascript에서는 가능해야하지만 C++에서는 가능하지 않은 이유는 없습니다. –

+0

분명히 QML로만 가능하지만 일정한 규모로 진행될 수 있습니다. QML 요소는 크기가 500 바이트 이상이면 좋은 크기입니다. 또한 QML API가 어린이를 재정렬하는 수단을 제공하지 않기 때문에 데이터 구조에 대한 현재 인프라를 재사용 할 수 있다고 생각하지 않습니다. 그리고 C++에서도 QML과 비교하여 실행되는 다른 방법을 설명하는 한 가능합니다. – dtech