从源码解析 QGraphicsItem 旋转、缩放、平移、transform等变换操作,利用QGraphicsTransform实现变形动画
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 结构体中,源码如下:
struct QGraphicsItemPrivate::TransformData
{
QTransform transform;// 对应setTransform()设置的值
qreal scale; // 对应setScale()设置的值
qreal rotation; // 对应setRotation()设置的值
qreal xOrigin;
qreal yOrigin;
QList<QGraphicsTransform *> graphicsTransforms; // 对应setTransformations()设置的设置的值
bool onlyTransform;
TransformData() :
scale(1.0), rotation(0.0),
xOrigin(0.0), yOrigin(0.0),
onlyTransform(true)
{ }
QTransform computedFullTransform(QTransform *postmultiplyTransform = nullptr) const
{
// 此处进行叠加运算
if (onlyTransform) {
if (!postmultiplyTransform || postmultiplyTransform->isIdentity())
return transform;
if (transform.isIdentity())
return *postmultiplyTransform;
return transform * *postmultiplyTransform;
}
QTransform x(transform);
if (!graphicsTransforms.isEmpty()) {
QMatrix4x4 m;
for (int i = 0; i < graphicsTransforms.size(); ++i)
graphicsTransforms.at(i)->applyTo(&m);
x *= m.toTransform();
}
x.translate(xOrigin, yOrigin);
x.rotate(rotation);
x.scale(scale, scale);
x.translate(-xOrigin, -yOrigin);
if (postmultiplyTransform)
x *= *postmultiplyTransform;
return x;
}
};
从源码中可以看出,transform、scale、rotation、graphicsTransforms单独存储。通过setRotation()设置的值存储在rotation,通过setScale()设置的值存储在scale。而rotation()和scale()返回的值就是QGraphicsItemPrivate中的变量rotation和scale。从qgraphicsitem.cpp源码中可以看到rotation和scale的存储方法。
qreal QGraphicsItem::rotation() const
{
if (!d_ptr->transformData)
return 0;
return d_ptr->transformData->rotation;
}
void QGraphicsItem::setRotation(qreal angle)
{
prepareGeometryChange();
qreal newRotation = angle;
if (d_ptr->flags & ItemSendsGeometryChanges) {
// Notify the item that the rotation is changing.
const QVariant newRotationVariant(itemChange(ItemRotationChange, angle));
newRotation = newRotationVariant.toReal();
}
if (!d_ptr->transformData)
d_ptr->transformData = new QGraphicsItemPrivate::TransformData;
if (d_ptr->transformData->rotation == newRotation)
return;
d_ptr->transformData->rotation = newRotation;
d_ptr->transformData->onlyTransform = false;
d_ptr->dirtySceneTransform = 1;
// Send post-notification.
if (d_ptr->flags & ItemSendsGeometryChanges)
itemChange(ItemRotationHasChanged, newRotation);
if (d_ptr->isObject)
emit static_cast<QGraphicsObject *>(this)->rotationChanged();
d_ptr->transformChanged();
}
如果需要获取当前图元旋转的角度,从 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 实现了旋转、水平翻转、垂直翻转、按路径移动、缩放等动画效果。

从源码解析 QGraphicsItem 旋转、缩放、平移、transform等变换操作,利用QGraphicsTransform实现变形动画的更多相关文章
- Netty 源码解析(八): 回到 Channel 的 register 操作
原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365篇原创计划”第八篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源 ...
- Laravel源码解析--看看Lumen到底比Laravel轻在哪里
在前面一篇<Laravel源码解析--Laravel生命周期详解>中我们利用xdebug详细了解了下Laravel一次请求中到底做了哪些处理.今天我们跟 Lumen 对比下,看看 Lume ...
- Netty 源码解析(三): Netty 的 Future 和 Promise
今天是猿灯塔“365篇原创计划”第三篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源码解析(二): Netty 的 Channel 当前:Ne ...
- Netty 源码解析(九): connect 过程和 bind 过程分析
原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365篇原创计划”第九篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源 ...
- Netty 源码解析(七): NioEventLoop 工作流程
原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365篇原创计划”第七篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源 ...
- Netty 源码解析(六): Channel 的 register 操作
原创申明:本文由公众号[猿灯塔]原创,转载请说明出处标注 今天是猿灯塔“365篇原创计划”第六篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一 ):开始 Netty ...
- Netty 源码解析(五): Netty 的线程池分析
今天是猿灯塔“365篇原创计划”第五篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源码解析(二): Netty 的 Channel Netty ...
- Netty 源码解析(四): Netty 的 ChannelPipeline
今天是猿灯塔“365篇原创计划”第四篇. 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty 源码解析(一): 开始 Netty 源码解析(二): Netty 的 Channel Netty ...
- Netty 源码解析(二):Netty 的 Channel
本文首发于微信公众号[猿灯塔],转载引用请说明出处 接下来的时间灯塔君持续更新Netty系列一共九篇 Netty源码解析(一):开始 当前:Netty 源码解析(二): Netty 的 Channel ...
- Netty系列之源码解析(一)
本文首发于微信公众号[猿灯塔],转载引用请说明出处 接下来的时间灯塔君持续更新Netty系列一共九篇 当前:Netty 源码解析(一)开始 Netty 源码解析(二): Netty 的 Channel ...
随机推荐
- HBase的Memstore-schema-rowkey设计原则
schema设计原则 前提条件 使用HBase Shell或者Java API的HBaseAdmin来创建和编辑HBase的Schema,当修改列簇时,建议先将这张表下线. Configurati ...
- w3cschool-Go 教程
https://www.w3cschool.cn/go/ Go 是一个开源的编程语言,它能让构造简单.可靠且高效的软件变得容易. Go是从2007年末由Robert Griesemer, Rob Pi ...
- JS获取字符串长度的常用方法,汉字算两个字节
JS获取字符串实际长度(双字节字符.汉字算两个字符) //第一种 GetLength = function(str) { var realLength = 0; for (var i = 0; i & ...
- 富数-AnonymFL
本文学习文章"2022 WAIC|「全匿踪联邦学习」AnonymFL正式发布:破解用户ID暴露难题,实现真正合规可信的隐私计算",记录笔记. 引言 2022年08月26日,富数科技 ...
- 0424-字节输出流FileOutputStream
package A10_IOStream; import java.io.FileOutputStream; import java.io.IOException; import java.util. ...
- uni-app组件 信息列表组件
之前我一直在,要想提高自己的代码质量, 就一定要封装自己的组件, 所以我就尽量使用自己的组件.这样可以提高自己的效率 写组件的好处:减少代码的冗余 封装组件的时候,为了不让子元素的padding, 影 ...
- AI定制祝福视频,广州塔、动态彩灯、LED表白,直播互动新玩法(附下载链接)
在追剧的时候经常能看到一些浪漫的告白桥段,男主用圣诞彩灯表白.用城市标志性建筑的LED表白,或者在五光十色的烟花绽放后刻下女主角的名字,充满了仪式感和氛围感~ 现在,这样的表白效果用AI软件就能实现了 ...
- 创新突破!天翼云荣膺CCF HPC China 2024高性能计算创新大奖
近日,第20届CCF全国高性能计算学术年会(CCF HPC China 2024)在武汉隆重召开.CCF HPC China是全球高性能计算领域三大标志性盛会之一,本届大会以"华章廿载 新质 ...
- 解锁数据潜力,天翼云TeleDB为企业数智蝶变添力赋能!
近日,第15届中国数据库技术大会(DTCC2024)在北京召开.大会以"自研创新 数智未来"为主题,重点围绕向量数据库与向量检索技术实践.数据治理与数据资产管理.云原生数据库开发与 ...
- 云电脑:IO虚拟化实现的技术分析
本文分享自天翼云开发者社区<云电脑:IO虚拟化实现的技术分析>,作者:大利 云电脑是一种基于云计算技术的虚拟化电脑,它通过网络将物理硬件资源虚拟化成多个虚拟机,每个虚拟机都拥有独立的操作系 ...