概述
The Graphics View Coordinate System 图形视图坐标系统是Qt图形视图框架的重要组成部分,按照帮助文档中的划分,其与 The Graphics View Architecture 图形视图架构是在一个层级上的,主要包含图形项坐标系、场景坐标系、视图坐标系、坐标映射等内容。本文将结合帮助文档、Qt编程书籍、Qt示例程序等研习图形视图框架坐标系统的设计理念和使用方法。
补充,20230501,
编写HelpDoc的人,大概率是极为熟悉该模块的开发者,他们编写文档时的立意是全局化的,很有可能在写第一个章节时,潜移默化的渗透少许第二、甚至第三四五章节的知识点,尽管他们可能已经在尽力避免类似事情的发生,但那很难做到。所以有很多帮助内容,初读时很有跳跃感,比较吃力。此时先读个大概,了解全局,再回头细读,可能是一种可行的方法。
转载请标明原文链接,
https://blog.csdn.net/quguanxin/category_12597847.html
Qt 坐标系统
图形视图框架的坐标系统基于Qt大框架的坐标系统。逻辑坐标系的使用,使绘制代码独立于绘画设备的分辨率和坐标系,开发者可以在逻辑坐标系中编写绘制代码,QPainter 会自动将其映射到实际的设备坐标系。
在Qt框架下,QPainter类实际掌控着Qt坐标系统,并且它与 QPaintDevice 和 QPaintEngine 类共同组成了Qt的绘制系统,而且Qt绘制系统竟然还有一个名字,Arthur 亚瑟,这可能是一个项目代号,具体不得而知。QPainter 用以执行绘制操作,QPaintDevice 是一个二维绘制空间,QPainter就是在该空间进行绘制操作,QPaintEngine为painter在不同设备上的绘制操作提供了interface接口。
QPaintDevice类是所有支持绘制的类的基类,它的绘画能力被 QWidget, QImage, QPixmap, QPicture, and QOpenGLPaintDevice 继承。一个Qt绘制设备的默认坐标系原点在Device左上角,X轴向右增长,Y轴向下增长。在基于像素的设备上,以像素为默认长度单位,在打印设备上,默认单位是一个点(1/72英寸)。QPainter的逻辑坐标到QPaintDevice的物理坐标的映射,由QPainter的变换矩阵、视口和窗口处理。
图形视图坐标系统以Qt坐标系统为基础,不支持y轴向上增长的反向坐标系(inverted Y-axis coordinate system)。在传统的笛卡尔坐标系中,坐标原点 (0,0) 位于左下角,y轴向上增长,也就是说 y 值越大,坐标点在垂直方向上越高。而在Qt中采用Y轴向下增长,其原因可能是,在绘制图像时,通常图像的第一行像素位于最上方,向下递增,这符合存储图像数据的方式,如此更加自然。
图形视图的渲染过程
前边提到过,图形视图使用Qt的坐标系统,上述图片段落大意是将图形视图框架的渲染过程代入了 Qt 绘制系统。Qt图形视图框架下,在渲染时,图形视图的场景坐标对应于QPainter的逻辑坐标,视图坐标等同于设备坐标。有关逻辑坐标和设备坐标之间关系的更多内容,在Qt绘制系统的相关文章中讲述。在 ‘绘制’ 这个层次的概念上,Qt图形视图框架并没有脱离QPainter机制,而是在QPainter的基础上进行了扩展和封装,如,自动处理场景的渲染和重绘。
在图形视图中有三个有效effective的坐标系统:图形项坐标系、场景坐标系和视图坐标系。为了简化实现,Qt 图形视图提供了便利函数,允许您在三个坐标系统之间进行映射。
Item图形项坐标系
Item居于live自己的本地坐标系中,可以理解为Item在自己的本地坐标系中运作。图形项坐标系通常以项的中心点 (0,0) 为中心(注意,有的不是哦,后文有提及),这个点也是所有坐标变换的中心。图形项坐标系下的几何图元(Geometric primitives) 通常被称为,点、Item线、Item矩形。
当你创建一个自定义项时,你只需要关注Item本地坐标系即可,场景和视图会帮你执行所有变换。如在 Diagram Scene Example 示例程序中,创建基本流程图形状的代码,是在Item本地坐标系中进行绘制的,根本不用关心场景和视图坐标系的任何。
DiagramItem::DiagramItem(DiagramType diagramType, QMenu *contextMenu, QGraphicsItem *parent) : QGraphicsPolygonItem(parent) {
...
switch (myDiagramType) {
...
case Conditional: //流程图形状,判定框
myPolygon << QPointF(-100, 0) << QPointF(0, 100)
<< QPointF(100, 0) << QPointF(0, -100)
<< QPointF(-100, 0);
break;
case Step: //流程图形状,过程框
myPolygon << QPointF(-100, -100) << QPointF(100, -100)
<< QPointF(100, 100) << QPointF(-100, 100)
<< QPointF(-100, -100);
break;
...
}
setPolygon(myPolygon);
...
}
Qt 图形视图框架在尽力的使用Item本地坐标系坐标交互位置信息,以方便开发者使用。例如,当你 (潜台词,在Item对象中) 接收到鼠标按下或拖拽进入事件时,事件(QGraphicsSceneMouseEvent)对象携带的位置会以Item坐标给出(到图形项对象)。QGraphicsItem::contains() 虚函数用于判断某个点是否在物品内,如果在则返回 true,否则返回 false,该函数的参数为Item坐标系下的坐标。类似地,Item的边界矩形和形状也是以Item坐标表示的。下文以 mousePressEvent 鼠标事件为例,观察该事件在视图、场景和图形项中的运行规律,
//在图形项QGraphicsItem类中
virtual void QGraphicsItem::mousePressEvent(QGraphicsSceneMouseEvent *event);
//在场景QGraphicsScene类中
virtual void QGraphicsScene::mousePressEvent(QGraphicsSceneMouseEvent *event);
//是视图QGraphicsView类中
virtual void QGraphicsView::mousePressEvent(QMouseEvent *event);
如上函数同为mousePressEvent原型,QGraphicsView 使用QWidget传统的QMouseEvent 事件类型,而 QGraphicsItem 和 QGraphicsScene 使用 QGraphicsSceneMouseEvent 事件类型,后者可传递两种位置信息,如下,
相关示例代码,放在了后续 ‘View视图坐标系’ 章节中。通过调试信息可确认,在Item对象中接收到的mouseEvent事件,通过 mouseEvent->pos 函数传递出来的是Item坐标系下的坐标。
父坐标 和 子坐标, (同一个视觉位置点的父坐标和子坐标)
不得不穿插对英语句子的理解,只是个人理解,原谅我英语没学好,
At item’s position is the coordinate of the item’s center point in its parent’s coordinate system。
结合上图中QGraphicsItem的构造函数,对上文的一个合理的释义,可能是,“(this这个) Item 的位置” 是指 (this) Item 的中心点在其父级(父Item) 坐标系中的坐标,有时也简称为父坐标。从某种意义上来说,若一个Item没有任何父(Item),那么场景将被当做是它的父(Item),顶层Item的位置以场景坐标来表示。整体上,这一小段Doc,目的是传递一个父坐标的概念,即,Item的(pos函数)位置是该Item原点在其父Item坐标系中的坐标。