从源码解析 QGraphicsItem 旋转、缩放、平移、transform等变更操作,利用QG ...

打印 上一主题 下一主题

主题 1621|帖子 1621|积分 4863

QGraphicsItem 有3种方式进行变更:1. 最简单方便的是使用 setRotation() 、setScale();2. 使用 setTransform() 进行复杂变更;3. 还可以使用 setTransformations()进行多项组合变更及自界说变更。同时应用这三种方式将产生叠加效果,并以 QTransform 形式返回。由于QTransform 是以矩阵为底子进行运算,所以叠加时运算的顺序将影响最后的运算效果。       QGraphicsItem 叠加变更时按照如下顺序进行:首先,应用 setTransform() 设置的 transform;其次,叠加运算 setTransformations() 设置的 transformations(按照 list 中的顺序执行);然后,叠加运算 setRotation() 设置的 rotation;最后,叠加运算 setScale()设置的 scale。这些规则表现在 qgraphicsitem_p.h 中的 QGraphicsItemPrivate 结构体中,源码如下:
  1. struct QGraphicsItemPrivate::TransformData
  2. {
  3.     QTransform transform;// 对应setTransform()设置的值
  4.     qreal scale; // 对应setScale()设置的值
  5.     qreal rotation; // 对应setRotation()设置的值
  6.     qreal xOrigin;
  7.     qreal yOrigin;
  8.     QList<QGraphicsTransform *> graphicsTransforms; // 对应setTransformations()设置的设置的值
  9.     bool onlyTransform;
  10.     TransformData() :
  11.         scale(1.0), rotation(0.0),
  12.         xOrigin(0.0), yOrigin(0.0),
  13.         onlyTransform(true)
  14.     { }
  15.     QTransform computedFullTransform(QTransform *postmultiplyTransform = nullptr) const
  16.     {
  17.         // 此处进行叠加运算
  18.         if (onlyTransform) {
  19.             if (!postmultiplyTransform || postmultiplyTransform->isIdentity())
  20.                 return transform;
  21.             if (transform.isIdentity())
  22.                 return *postmultiplyTransform;
  23.             return transform * *postmultiplyTransform;
  24.         }
  25.         QTransform x(transform);
  26.         if (!graphicsTransforms.isEmpty()) {
  27.             QMatrix4x4 m;
  28.             for (int i = 0; i < graphicsTransforms.size(); ++i)
  29.                 graphicsTransforms.at(i)->applyTo(&m);
  30.             x *= m.toTransform();
  31.         }
  32.         x.translate(xOrigin, yOrigin);
  33.         x.rotate(rotation);
  34.         x.scale(scale, scale);
  35.         x.translate(-xOrigin, -yOrigin);
  36.         if (postmultiplyTransform)
  37.             x *= *postmultiplyTransform;
  38.         return x;
  39.     }
  40. };
复制代码
从源码中可以看出,transform、scale、rotation、graphicsTransforms单独存储。通过setRotation()设置的值存储在rotation,通过setScale()设置的值存储在scale。而rotation()和scale()返回的值就是QGraphicsItemPrivate中的变量rotation和scale。从qgraphicsitem.cpp源码中可以看到rotation和scale的存储方法。
  1. qreal QGraphicsItem::rotation() const
  2. {
  3.     if (!d_ptr->transformData)
  4.         return 0;
  5.     return d_ptr->transformData->rotation;
  6. }
  7. void QGraphicsItem::setRotation(qreal angle)
  8. {
  9.     prepareGeometryChange();
  10.     qreal newRotation = angle;
  11.     if (d_ptr->flags & ItemSendsGeometryChanges) {
  12.         // Notify the item that the rotation is changing.
  13.         const QVariant newRotationVariant(itemChange(ItemRotationChange, angle));
  14.         newRotation = newRotationVariant.toReal();
  15.     }
  16.     if (!d_ptr->transformData)
  17.         d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
  18.     if (d_ptr->transformData->rotation == newRotation)
  19.         return;
  20.     d_ptr->transformData->rotation = newRotation;
  21.     d_ptr->transformData->onlyTransform = false;
  22.     d_ptr->dirtySceneTransform = 1;
  23.     // Send post-notification.
  24.     if (d_ptr->flags & ItemSendsGeometryChanges)
  25.         itemChange(ItemRotationHasChanged, newRotation);
  26.     if (d_ptr->isObject)
  27.         emit static_cast<QGraphicsObject *>(this)->rotationChanged();
  28.     d_ptr->transformChanged();
  29. }
复制代码
如果须要获取当前图元旋转的角度,从 rotation() 方法中的得到的角度只是通过 setRotation() 方法设置的角度,该角度不包含 transform 和 graphicsTransforms 中隐含的角度。固然,如果图元只是进行了角度变更,可以从 sceneTransform() 方法获取 Transform,利用文章《Qt 从 QTransform 逆向解出 Translate/Scale/Rotate(平移/缩放/旋转)分析》介绍的方法可以逆向解析出图元旋转的角度。
如果须要获取图元每次变革的角度、缩放大小及平移信息,可以只使用 setTransformations() 方法来控制图元进行变革,因为 QGraphicsTransform 的子类可以完全由开发者自己控制,所执行的变更都可以很轻易的计算出来。例如:QGraphicsTransform 的子类 QGraphicsRotation 提供了 angle() 和 setAngle(qreal) 方法;QGraphicsScale 提供了 setXScale(qreal) 、xScale() const 、setYScale(qreal) 、yScale() const 等方法。
控制图元变更时 setTransformations() 方法更灵活一些,特别是对图元进行变更动画时,编写 QGraphicsTransform 的子类,很轻易控制动画。具体代码可以参考GitHub项目 Compelling Data Designer 中 BIDesigner/animation
/tranfromanimation 的实现方法。通过扩展 QGraphicsTransform 实现子类 GraphicsRotationZ 、 GraphicsRotationY 、 GraphicsRotationX 、 QGraphicsTranslation 实现了旋转、水平翻转、垂直翻转、按路径移动、缩放等动画效果。


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

涛声依旧在

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表