Не удается анимировать QTransform в qgraphicsItem

Я пытаюсь сделать 3D-анимацию в GraphicsScene, например, для поворота изображений в GraphicsScene (используя класс, подкласс из qPixmapItem и QObject, если это имеет значение) с помощью Animation framework.

Все работает нормально, пока я не хочу вращать изображения вокруг вертикальной оси. Невозможно сделать это через item.rotate(), поэтому я использую QTranform.

Проблема в том, что это вообще ничего не анимирует. Что я делаю неправильно?

P.S. Я не хочу использовать для этого OpenGl.

Вот как я это делаю. Этот способ работает для анимации более простых свойств, таких как pos, вращение (через rotation, setRotation)

Мой код:

// hybrid graphicsSceneItem, supporting animation 
class ScenePixmap : public QObject, public QGraphicsPixmapItem
{
    Q_OBJECT
    Q_PROPERTY(QTransform transform READ transform WRITE setTransform)
public:
    ScenePixmap(const QPixmap &pixmap, QObject* parent = NULL, QGraphicsItem* parentItem = NULL):
        QObject(parent),
        QGraphicsPixmapItem(pixmap, parentItem)

    {}
};

Вот как я настраиваю сцену и анимацию:

//setup scene
//Unrelated stuff, loading pictures, etc.
            scene = new QGraphicsScene(this);
        foreach(const QPixmap& image, images)
        {
            ScenePixmap* item = new ScenePixmap(image);
            item->moveBy(70*i, 0);
            i++;
            this->images.append(item);
            scene->addItem(item);
        }
    }

    ui->graphicsView->setBackgroundBrush(QBrush(Qt::black, Qt::SolidPattern));
    ui->graphicsView->setScene(scene);

    //setup animation
QTransform getTransform()
{
    QTransform transform;
    transform.rotate(-30, Qt::ZAxis);//also tried transform = transform.rotate(...)

    return transform;
}

QAbstractAnimation* SetupRotationAnimation(ScenePixmap* pixmapItem)
{
    QPropertyAnimation* animation = new QPropertyAnimation(pixmapItem, "transform");
    animation->setDuration(1400);
    animation->setStartValue( pixmapItem->transform());
    animation->setEndValue(getTransform());//here i tried to multiply with default transform , this does not work either
    return animation;
}

вот как я запускаю анимацию:

void MainWindow::keyPressEvent ( QKeyEvent * event )
{

    if((event->modifiers() & Qt::ControlModifier))
    {
        QAnimationGroup* groupAnimation = new QParallelAnimationGroup();


        foreach(ScenePixmap* image, images)
        {
            groupAnimation->addAnimation( SetupRotationAnimation(image));

        }

        groupAnimation->start(QAbstractAnimation::DeleteWhenStopped);

    }
}

РЕДАКТИРОВАТЬ [Решено] спасибо Дарко Максимовичу:

Вот код, который у меня сработал:

QGraphicsRotation* getGraphicRotation()
{
    QGraphicsRotation* transform = new QGraphicsRotation(this);

    transform->setAxis(Qt::YAxis);

    return transform;
}

QAbstractAnimation* SetupRotationAnimation(ScenePixmap* pixmapItem)
{
    QGraphicsRotation* rotation = getGraphicRotation();

    QPropertyAnimation* animation = new QPropertyAnimation(rotation, "angle");
    animation->setDuration(1400);
    animation->setStartValue( 0);
    animation->setEndValue(45);

    pixmapItem->setTransformOriginPoint(pixmapItem->boundingRect().center());

    QList<QGraphicsTransform*> transfromations = pixmapItem->transformations();
    transfromations.append(rotation);
    pixmapItem->setTransformations(transfromations);

    return animation;
}

person undefined    schedule 14.05.2012    source источник
comment
Куда ты звонишь SetupRotationAnimation?   -  person Stefan Majewsky    schedule 14.05.2012
comment
Вы знаете, я честно не могу решить, является ли transfromations умным каламбуром (для списка существующих преобразований, которые вы загружаете из растрового изображения )... или просто та же опечатка, повторенная трижды.   -  person FeRD    schedule 21.03.2020


Ответы (2)


Я вижу, вы используете QTransform. Если вам нужен только один поворот, то есть простой поворот, лучше использовать setRotation [не забывайте о setTransformOriginPoint].

Однако если вы хотите запомнить множество поворотов, например, вокруг разных точек преобразования, вам следует использовать QGraphicsTransform, то есть его специализированный производный класс QGraphicsRotation, который вы применяете с помощью вызов setTransformations для графического объекта (вы должны сначала получить существующие преобразования, вызвав o.transformations(), добавить к этому, а затем вызвать setTransformations; если вы сохраните указатель на добавленное преобразование, вы также можете изменить это позже непосредственно).

Из кода, который вы разместили, я не вижу, откуда берется ваша ошибка, но с помощью специализированных функций вы можете избежать некоторых частых проблем.

P.S. Я также вижу, что вы не использовали prepareGeometryChange в опубликованном вами коде, поэтому имейте в виду, что это необходимо при преобразовании объектов.

person Darko Maksimovic    schedule 14.05.2012
comment
Получилось, спасибо! Я обновлю вопрос, чтобы указать решение - person undefined; 15.05.2012
comment
Не лучше анимировать вращение, иначе просто не получится - по дизайну. - person Kuba hasn't forgotten Monica; 31.08.2013

Проблема очень проста. QVariantAnimation и QPropertyAnimation не поддерживают QTransform. Черт возьми, они даже не поддерживают целые числа без знака на данный момент. Вот и все. Документация по Qt:

Если вам нужно интерполировать другие типы вариантов, включая пользовательские типы, вы должны реализовать для них интерполяцию самостоятельно. Для этого вы можете зарегистрировать функцию интерполятора для данного типа. Эта функция принимает 3 параметра: начальное значение, конечное значение и текущий прогресс.

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

Тот факт, что QVariant может содержать тип, не означает, что он поддерживается интерполятором по умолчанию. Вероятно, для этого должно быть выдано предупреждение во время выполнения.

person Kuba hasn't forgotten Monica    schedule 30.08.2013