触发属性更改的QML动画

时间:2014-10-16 01:06:57

标签: c++ qt qml

我正在使用一些CPU密集型代码实现应用。此代码必须更新QML中设计的界面以显示其结果。

界面由网格和几个块组成,其中包含一些内容。 Grid完全由C ++实现,Block仅为QML。

Block.qml

import QtQuick 2.3

Item {
    id: root

    // lot of non-related stuff here.

    Behavior on x {
        NumberAnimation {
            duration: 1000
            easing.type: Easing.Linear

            onRunningChanged: {
                console.log("behavior on x");
            }
        }
    }

    Behavior on y {
        NumberAnimation {
            duration: 1000
            easing.type: Easing.Linear

            onRunningChanged: {
                console.log("behavior on y");
            }
        }
    }
}

每个块都是用C ++创建的,并相应定位。

问题是有时我必须移动块,我想触发一个动画。要做到这一点,我已经包含了你可能已经注意到的Behavior元素。

但是当我从C ++代码更改块的位置时,不会触发该行为。 Block只是改变了它的位置,没有任何动画。

我用来改变块位置的代码是:

void Grid::setBlockPosition(QQuickItem *block, unsigned i, unsigned j)
{
    float x, y;
    x = GRID_MARGIN_LEFT + j * this->_blockSize;
    y = GRID_MARGIN_TOP + (GRID_ROWS - i - 1) * this->_blockSize;
    block->setPosition(QPointF(x, y));
}

我还尝试更改x然后更改y,而不是同时更改两者,但结果相同。

如何从C ++触发xy属性的行为?

1 个答案:

答案 0 :(得分:5)

这是一个很好的问题。我查看了QQuickItem的来源,setX()setY()setPosition()都有非常相似的代码路径,所有代码路径都发出geometryChanged()。您可能认为这就足够了,但事实证明it's not

  

您应该始终使用QObject :: setProperty(),QQmlProperty或QMetaProperty :: write()来更改QML属性值,以确保QML引擎知道属性更改。例如,假设您有一个带有buttonText属性的自定义类型PushButton,该属性在内部反映了m_buttonText成员变量的值。直接修改成员变量[...]不是一个好主意[...]。

     

由于该值是直接更改的,因此绕过Qt的元对象系统,并且QML引擎无法识别属性更改。这意味着不会更新对buttonText的属性绑定,也不会调用任何onButtonTextChanged处理程序。

使用特定于您的代码的示例:例如,如果您在QML中更改块的x属性,则元对象系统会知道更改并且Behavior会收到通知并设置属性直接,以增量,直到达到目标。当您自己直接设置属性时,Behavior不知道任何内容发生了变化,因此它什么也没做。

因此,您应该致电setProperty("x", x)setProperty("y", y)

#include <QApplication>
#include <QtQuick>
#include <QtQml>

class Grid : public QQuickItem
{
    Q_OBJECT
public:
    Grid(QQuickItem *parent) {
        setParentItem(parent);
    }

public slots:
    void addBlocks() {
        QQmlComponent *blockComponent = new QQmlComponent(qmlEngine(parentItem()), "Block.qml");
        for (int i = 0; i < 4; ++i) {
            QQuickItem *block = qobject_cast<QQuickItem*>(blockComponent->create());
            Q_ASSERT(!blockComponent->isError());
            block->setParentItem(this);
            block->setProperty("x", i * 100);
            block->setProperty("y", i * 100);
            mBlocks.append(block);
        }
    }

private:
    QList<QQuickItem*> mBlocks;
};

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);

    QQmlApplicationEngine engine;
    engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

    QQuickItem *contentItem = engine.rootObjects().first()->property("contentItem").value<QQuickItem*>();
    Grid *grid = new Grid(contentItem);
    grid->addBlocks();

    return a.exec();
}

#include "main.moc"

added this了解QQuickItem文档详细说明的信息;希望其他人看到这个,如果他们遇到这个问题。