【问题标题】:QPropertyAnimation of a QGraphicsTextItem with a frame make the text shaky带有框架的 QGraphicsTextItem 的 QPropertyAnimation 使文本抖动
【发布时间】:2019-03-22 00:59:10
【问题描述】:

我正在为 QGraphicsTextItem 设置动画,我在其周围添加了一个框架。在动画期间,文本似乎在框架内轻微晃动,这很烦人。

示例代码:

class MovingFrameText : public QGraphicsTextItem
{
    Q_OBJECT;

   public:
      MovingFrameText( ) : QGraphicsTextItem(0)
      {
         setPlainText ( "human ");
         QFont f =  font();
         f.setPixelSize(40);
         setFont(f);
         setFlags(QGraphicsItem::ItemIsMovable);
      }

      QRectF boundingRect() const
      {
         return QGraphicsTextItem::boundingRect().adjusted(-2,-2,+2,+2);
      }

      void paint(QPainter *painter,const QStyleOptionGraphicsItem *option,QWidget *widget)
      {
         QGraphicsTextItem::paint(painter,option,widget);
         painter->setPen(Qt::black);
         painter->drawRect(boundingRect());
      }

};

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


   MovingFrameText t;
   t.setPos(640,680);

   QGraphicsScene scene;
   scene.addItem(&t);

   QGraphicsView view(&scene);
   view.resize(640, 680);
   view.show();

    auto moveAnimation = new QPropertyAnimation( &t,  "pos" );
    moveAnimation->setDuration( 10000 );
    moveAnimation->setStartValue( QPointF(640, 680) );
    moveAnimation->setEndValue(  QPointF(0, 0) );
    moveAnimation->setEasingCurve( QEasingCurve::Linear );
    moveAnimation->start(QAbstractAnimation::DeleteWhenStopped);

 return app.exec();
}

有什么办法可以平滑动画吗?

【问题讨论】:

  • 顺便说一句,你为什么要定义一个新的pos 属性。 QGraphicsTextItem 已经有一个从 QGraphicsObject 继承的 pos 属性。
  • 它只是我做的另一个测试代码的剩余部分。我将它编辑出来,但它不会改变结果,文本在框中晃动。

标签: c++ qt qt5 qgraphicstextitem qpropertyanimation


【解决方案1】:

解决方案

您可以通过以下方式大幅改进动画:

  1. 使用QVariantAnimation 代替QPropertyAnimation 并在每次迭代中调用QGraphicsItem::update
  2. 使用额外的QPainterQPixmap 作为所有绘画操作的画布缓冲绘画,然后使用传递给paint 方法的画家绘画画布

注意:QGraphicsTextItem 仍然会晃动一点,但至少它会表现为一个对象,而不是几个独立的对象。

示例

这是我为您准备的一个示例,说明如何更改您的代码以实施建议的解决方案:

class MovingFrameText : public QGraphicsTextItem
{
public:
    MovingFrameText(const QString &text, QGraphicsItem *parent = nullptr)
        : QGraphicsTextItem(parent)
    {
        QFont f(font());

        f.setPixelSize(40);

        setFont(f);
        setPlainText(text);
    }

    void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
    {
        painter->setClipping(true);
        painter->setClipRect(option->rect);
        painter->setRenderHint(QPainter::SmoothPixmapTransform);

        QPixmap canvas(option->rect.size());
        QPainter canvasPainter;

        canvas.fill(Qt::transparent);

        canvasPainter.begin(&canvas);

        canvasPainter.setFont(font());
        canvasPainter.drawRect(option->rect.adjusted(0, 0, -1, -1));
        canvasPainter.drawText(option->rect, toPlainText());

        painter->drawPixmap(0, 0, canvas);
    }
};

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

    QGraphicsView view;
    auto *t = new MovingFrameText("human");

    view.setScene(new QGraphicsScene(&view));
    view.setAlignment(Qt::AlignLeft | Qt::AlignTop);
    view.setSceneRect(0, 0, 640, 680);
    view.scene()->addItem(t);
    view.show();

    auto *moveAnimation = new QVariantAnimation();

    moveAnimation->setDuration(10000);
    moveAnimation->setStartValue(QPointF(640, 680));
    moveAnimation->setEndValue(QPointF(0, 0));
    moveAnimation->start(QAbstractAnimation::DeleteWhenStopped);

    QObject::connect(moveAnimation, &QVariantAnimation::valueChanged, [t](const QVariant &value){
        t->setPos(value.toPointF());
        t->update();
    });

    return app.exec();
}

【讨论】:

  • 感谢您的回答。我用我正在研究的解决方案对其进行了测试,它似乎具有类似的效果。通过添加“Q_PROPERTY(QPointF pos READ pos WRITE setPosition)”并铺设 QPointF。我也会为此添加一个解决方案。
  • @plover,你测试过我提供的代码吗?然后消除闪烁。此外,添加Q_PROPERTY( QPointF pos READ pos WRITE setPosition ) 不会导致闪烁。
  • 是的,我已经同时测试了我的新解决方案和您的解决方案。两者都显示出有希望的结果。我必须在我的代码库中对其进行测试(这只是一个很小的示例代码),看看那里有什么更好的地方。
  • @plover,复制MovingFrameText::paint的内容就够了。
【解决方案2】:

@scopchanov 的回答非常好。我在这里添加了一个我也测试过的解决方案,并且似乎有效。我将需要更多时间来检查我认为哪个更好,但如果您以类似的问题结束,我会将其留在这里供其他人尝试。

class MovingFrameText : public QGraphicsTextItem
{

   Q_PROPERTY( QPointF pos READ pos WRITE setPosition )
   public:

    void setPosition(QPointF pos)
    {
       setPos(floor(pos.x()+0.5),floor(pos.y()+.5) );
    }

};

【讨论】:

  • 两者结合怎么样?我的意思是缓冲绘画操作并为位置铺地板。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-02-06
  • 1970-01-01
  • 2016-04-12
  • 2014-07-29
  • 1970-01-01
相关资源
最近更新 更多