QML Shape: как я могу принудительно обновить свойство данных? - PullRequest
1 голос
/ 22 февраля 2020

Я пытаюсь создать окно, в котором я могу нарисовать треугольники и удалить любой из них с помощью Shape {} . В приведенном ниже примере я могу нарисовать 2 типа треугольника:

  • Треугольник вверх: зеленый и заполненный
  • Треугольник вниз: желтый и не заполненный

По сути, я выбираю тип треугольника (с кнопкой в ​​правом нижнем углу), затем нажимаю в любом месте окна, чтобы получить треугольник.

Когда я нажимаю, динамически создается треугольник, который сохраняется в свойстве triangleList . Затем я вызываю функцию shape.update () , чтобы обновить data свойство shape. Эта часть работает хорошо.

Здесь обновление функции, которое я использую в Shape (поскольку данные - это список, я должен переназначить новый список.):

function update()
{
    data = [];
    var d = [];

    for (var i = 0; i < canvas.triangleList.length; i++)
    {
       d.push( canvas.triangleList[i] );
    }
    data = d;
}

Появляется моя проблема когда я пытаюсь удалить треугольник. В моем примере я могу удалить первый, последний или все треугольники. Когда я удаляю треугольник, сначала я удаляю значение в triangleList , затем я снова вызываю shape.update () . Это работает, когда я удаляю все треугольники или последний.

Однако, когда я пытаюсь удалить первый треугольник, данные не обновляют свои объекты, даже если я даю ему новый список, На самом деле, он всегда удаляет последний треугольник. Ниже приведен пример:

enter image description here

свойство данных понимает, что на один треугольник меньше, но не обновляет другие треугольники. Единственное решение, которое я нашел, это изменить свойство, а затем вернуться к исходному значению. Таким образом, данные принудительно обновляются. Но я должен сделать это для каждого свойства , которое может быть различным (цвета и позиции). Следовательно, моя функция update () выглядит следующим образом:

for (var i = 0; i < canvas.triangleList.length; i++)
                {
    d.push( canvas.triangleList[i] );

    ////// Change properties one by one to force the refresh

    // Force path redraw. Otherwise only the last path can be deleted
    d[i].startX++;d[i].startX--;

    // Force line color update
    d[i].strokeColor = "red"
    d[i].strokeColor = d[i].isUp ? "green" : "yellow";

    // Force fill color update
    d[i].fillColor = "red";
    d[i].fillColor = d[i].isUp ? "green" : "transparent";

    data = d;
}

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

Поэтому мой вопрос: Есть ли способ принудительно обновить обновление без необходимости изменения каждое свойство?

Вот полный код, если вы хотите проверить его:

import QtQuick 2.9;
import QtQuick.Controls 2.2;
import QtQuick.Shapes 1.0;

ApplicationWindow {
    visible: true; width: 640; height: 480;

    Rectangle {
        id: canvas;
        anchors.fill: parent;
        color: "black";
        property var triangleList: [];
        property bool triangleUp: true;

        MouseArea {
            anchors.fill: parent;
            onClicked: {
                var triangle = componentTriangle.createObject(componentTriangle, {
                                                                "isUp" :  canvas.triangleUp,
                                                                "startX" :  mouse.x,
                                                                "startY" :  mouse.y,
                                                               }, canvas);

                canvas.triangleList.push(triangle);
                shape.update();
            }
        }   // MouseArea

        Shape {
            id: shape;

            anchors.fill: parent;

            function update()
            {
                data = [];
                var d = [];

                for (var i = 0; i < canvas.triangleList.length; i++)
                {
                    d.push( canvas.triangleList[i] );

                    ///////////// HOW TO AVOID THE PART BELOW? /////////////
                    ////// Change properties one by one to force the refresh

                    // Force path redraw. Otherwise only the last path can be deleted
                    d[i].startX++;d[i].startX--;

                    // Force line color update
                    d[i].strokeColor = "red"
                    d[i].strokeColor = d[i].isUp ? "green" : "yellow";

                    // Force fill color update
                    d[i].fillColor = "red";
                    d[i].fillColor = d[i].isUp ? "green" : "transparent";

                    //////////////////////////////////////////////////////
                }

                data = d;

                // I make sure data has at least one path to ensure the refresh
                if (data.length == 0)
                    data.push(Qt.createQmlObject('import QtQuick 2.9; import QtQuick.Shapes 1.0; ShapePath {startX:0;startY:0;}', canvas,
                              "force_refresh"));
            }
        }  // Shape
    }   // Rectangle

    //////////// Buttons to handle the triangles

    Column {
        anchors.bottom: parent.bottom;
        anchors.right: parent.right;

        Button {

            text: canvas.triangleUp? "Draw triangleUp" : "Draw triangleDown";
            onClicked: { canvas.triangleUp = !canvas.triangleUp; }
        }   // Button

        Button {
            text: "Clear first";
            onClicked: {
                canvas.triangleList[0].destroy();
                canvas.triangleList.splice(0,1);
                shape.update();
            }
        }   // Button

        Button {
            text: "Clear last";
            onClicked: {
                canvas.triangleList[canvas.triangleList.length -1].destroy();
                canvas.triangleList.splice(canvas.triangleList.length -1,1);
                shape.update();
            }
        }   // Button

        Button {
            text: "Clear all";
            onClicked: {
                for (var i = 0; i < canvas.triangleList.length; i++)
                    canvas.triangleList[i].destroy();
                canvas.triangleList = [];
                shape.update();
            }
        }   // Button
    }

    //////////// Component to draw the triangle
    Component {
        id: componentTriangle;

        ShapePath {
            property bool isUp;
            property real offsetX: isUp? -20 : 20;
            property real offsetY: isUp? -30 : 30;

            strokeColor: isUp ? "green" : "yellow";
            strokeWidth: 3;
            fillColor: isUp ? "green" : "transparent";

            PathLine { x: startX - offsetX; y: startY - offsetY }
            PathLine { x: startX + offsetX; y: startY - offsetY }
            PathLine { x: startX; y: startY }
        }   // ShapePath
    }
}

Большое спасибо за вашу помощь и не стесняйтесь спрашивать меня, если я не был ясен .

Хорошего дня!

1 Ответ

2 голосов
/ 23 февраля 2020

Если вы собираетесь обрабатывать много предметов (Shape), желательно использовать Повторитель с моделью. Повторитель отвечает за отображение элементов на основе информации о модели и за удаление элементов, вам просто нужно удалить элементы из модели.

main.qml

import QtQuick 2.9;
import QtQuick.Controls 2.2;
import QtQuick.Shapes 1.0;

ApplicationWindow {
    visible: true; width: 640; height: 480;
    QtObject{
        id: internals
        property bool triangleUp: true;
    }
    ListModel{
        id: datamodel
    }
    Rectangle {
        id: canvas;
        anchors.fill: parent;
        color: "black";
        Repeater{
            model: datamodel
            Triangle{
                x: model.x
                y: model.y
                isUp: model.isUp
            }
        }
        MouseArea{
            anchors.fill: parent
            onClicked: datamodel.append({"x": mouse.x, "y": mouse.y, "isUp": internals.triangleUp})
        }
    }
    Column {
        anchors.bottom: parent.bottom;
        anchors.right: parent.right;
        Button {
            text: internals.triangleUp ? "Draw triangleUp" : "Draw triangleDown";
            onClicked: internals.triangleUp = !internals.triangleUp;
        }   // Button

        Button {
            text: "Clear first";
            onClicked: if(datamodel.count > 0) datamodel.remove(0)
        }   // Button

        Button {
            text: "Clear last";
            onClicked: if(datamodel.count > 0) datamodel.remove(datamodel.count - 1)
        }   // Button

        Button {
            text: "Clear all";
            onClicked: datamodel.clear()
        }   // Button
    }
}

Triangle.qml

import QtQuick 2.9;
import QtQuick.Shapes 1.0

Shape {
    id: shape
    property bool isUp: false
    QtObject{
        id: internals
        property real offsetX: isUp? -20 : 20;
        property real offsetY: isUp? -30 : 30;
    }
    ShapePath {
        strokeWidth: 3;
        strokeColor: isUp ? "green" : "yellow";
        fillColor: isUp ? "green" : "transparent";
        PathLine { x: -internals.offsetX ; y: -internals.offsetY }
        PathLine { x: internals.offsetX; y: -internals.offsetY }
        PathLine { x: 0; y: 0 }
    }
}
...