目的:
对于刚了解QGraphics体系来说,基于QGraphicsView实现白板绘画曲线实现矢量绘画其实不难,然后基于非矢量绘画(通过绘画图片QImage)时,看了源代码后,结合经理所说方法,遇到两个问题,并被这两个问题弄蒙了,特意整理。
1、QPainter 不同。
1.1 自定义的图元(QGraphicsItem)中重写的paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)中QPainter主要是负责重新绘画Item(然后在item上绘画图片)。
1.2 item中QPainter painter(&m_pCanvas)主要是负责在画布(QImage上)绘画。
2、QImage地方用法错误。
2.1 QImage应该在自定义的图元中作为item,单独用重写paint()与boundingRect(),这个函数分别用来实现绘画item(重绘画Image)以及返回item的Rect。而不是自定义的在Scene使用。
2.2 QImage作为绘画的item,应该设置大小,虽然可能不报错,但是可能没法绘画具体Image。
总结:
对于要实现自定义的图元,我们必须重写paint()与boundingRect()这两个函数。这两个用来绘画你所需要的图元,以及图元碰撞坚持,边界设置。如上本质就是绘画图片图元,由于图片特殊性(继承自QPaintDevice),在图片图元上我们可以利用QPainter进行绘画,然后只需对图元paint()即可。同理其它QPainter安原理来说,也可以,但是性能不一样。
参考网址:https://blog.51cto.com/9291927/1879128
注意点
1、注意绘画曲线不能简单绘画直线、也不是简单点连线,否则容易绘画曲线有折线、容易间断画点。而应该采取相关算法(如贝尔斯曲线)进行曲线绘制。
2、明白QGraphicsView体系架构,明白QGraphicsView、QGraphicsScene、QGraphicsItem三者之间职责。
QGraphicsScene:
1、场景作为QGraphicsItem对象的容器,能对图元(自定义也可以)进行管理,为管理大量的items提供一个快速的接口。
2、传播事件(鼠标事件、键盘事件等)每个item。
3、管理item的状态,例如选择,焦点处理。 提供未经变换的渲染功能,主要用于打印。
QGraphicsView:
1、提供可视化场景、多个View可以监控同一个场景。
2、接受鼠标、键盘、resize等传来的事件,并传播给场景。
QGraphicsItem:
1、所有图元的父类、可以自定义图元。
2、QGraphicsItem支持以下特性: 鼠标按、移动、释放、双击事件,鼠标悬停事件,滚轮事件,弹出菜单事件。
3、父子关系(QGroup)
4、碰撞检测
3、体系之间坐标关系view scene item 三者之间坐标关系、事件传递顺序。
事件传递顺序:View->Scene->item
(如果item不能接受到鼠标事件)
可以考虑要设置(this->setAcceptedMouseButtons(Qt::LeftButton);
setFlag(QGraphicsItem::ItemIsSelectable);
三者之间坐标关系:
这个问题整理主要是因为,当时我直接在Item获取scenePos()好像总返回OPoint(0,0);然后整理这个问题,并梳理三者之间关系。
问题:
QGraphicsItem::scenePos() 总是返回QPointF(0,0)?
希望通过item的scenePos方法获得item在scene中的位置,结果总是返回(0,0)。
首先要搞清楚,在QT的Graphics中存在三个坐标系:item coordinates、scene coordinates、view coordinates。
item coordinates(图元坐标)
图元存在于自己的本地坐标上,图元的坐标系统通常以图元中心为原点,图元中心也是所有坐标变换的原点,图元坐标方向是x轴正方向向右,y轴正方向向下。创建自定义图元时,只需要注意图元的坐标,QGraphicsScene和QGraphicsView会完成所有的变换。 例如,如果接受到一个鼠标按下或拖入事件,所给的事件位置是基于图元坐标系的。如果某个点位于图元内部,使用图元上的点作为QGraphicsItem::contains()虚函数的参数,函数会返回true。类似,图元的边界矩形和形状也是基于图元坐标系。
图元的位置是图元的中心点在其父图元坐标系统的坐标。按这种说法,场景是所有无父图元的图元的父图元。顶层图元的位置是场景坐标。
子图元的坐标与父图元的坐标相关。如果子图元无变换,子图元坐标和父图元坐标之间的区别与他们的父图元的坐标相同。例如,如果一个无变换的子图元精确的位于父图元的中心点,父子图元的坐标系统是相同的。如果子图元的位置是(10,0),子图元上的点(0,10)就是父图元上的点(10,10)。
由于图元的位置和变换与父图元相关,但子图元的坐标并不会被父图元的变换影响,虽然父图元的变换会隐式地变换子图元。在上例中,即使父图元被翻转和缩放,子图元上的点(0,10)仍旧是父图元上的点(10,10)。
如果调用QGraphicsItem类的paint()函数重绘图元时,则以图元坐标系为基准。
scene coordinates(场景坐标)
场景坐标是所有图元的基础坐标系统。场景坐标系统描述了顶层图元的位置,并且构成从视图传播到场景的所有场景事件的基础。每个图元在场景上都有场景坐标和边界矩形。场景坐标的原点在场景中心,坐标原点是X轴正方向向右,Y轴正方向向下。
View coordinates (视图坐标 )
视图坐标是窗口部件的坐标,视图坐标的单位是像素,QGraphicsView的左上角是(0,0)。所有鼠标事件、拖拽事件最开始都使用视图坐标,为了和图元交互,需要转换坐标为场景坐标。
QGraphicsItem::pos() 指的是在父图元坐标下item位置
Returns the position of the item in parent coordinates. If the item has no parent, its position is given in scene coordinates.
The position of the item describes its origin (local coordinate (0, 0)) in parent coordinates; this function returns the same as mapToParent(0, 0).
QGraphicsItem::scenePos() 指的是在item在场景中位置
Returns the item’s position in scene coordinates. This is equivalent to calling mapToScene(0, 0).