这个类为编写用户的定制项目提供了一个轻量级的基础,包括定义项目的几何图形、碰撞检测和绘画以及通过事件处理进行的项目交互。QGraphicsItem是 Graphics View Framework 的一部分。
Qt为常见的形状提供了如下标准图形项。
提供椭圆项 | |
提供一个行项 | |
提供任意路径项 | |
提供一个位图项 | |
提供多边形项 | |
提供一个矩形项 | |
提供简单的文本标签项 | |
提供高级文本浏览器项 |
项目的所有几何信息都基于其局部坐标系。项目的位置 pos()是唯一不在本地坐标中操作的函数,因为它返回父坐标中的位置。 The Graphics View Coordinate System 详细描述QT坐标系。
您可以通过调用来 setVisible()设置某项是否可见(即绘制和接受事件),setVisible() 隐藏项目的同时也将隐藏其子项目。同样,您可以通过调用setEnabled(),如果禁用某个项目,其所有子项目也将被禁用。默认情况下,项目既是可见的又是启用的。若要切换某项是否被选中,首先通过设置 ItemIsSelectable 标志,然后调用 setSelected()。通常,用户交互的结果是场景切换选择。
要编写自己的图形项,首先要创建QGraphicsItem的子类,然后从实现它的两个纯虚拟公共函数开始:boundingRect(),它返回项目绘制区域的估计值,以及 paint(),它实现了实际的绘画。例如:
class SimpleItem : public QGraphicsItem //创建用户的图形项派生类
{
public:
//QRectF类使用浮点精度在平面中定义一个有限矩形。
//重新实现虚函数,为图形项外部定义一个矩形边界,所有绘画限制于框中
QRectF boundingRect() const override
{
//qreal其实就是double;在嵌入设备系统则等同于float。
qreal penWidth = 1;
return QRectF(-10 - penWidth / 2, -10 - penWidth / 2,
20 + penWidth, 20 + penWidth);
}
//重新实现虚函数,以局部坐标绘制项的内容。
void paint(QPainter *painter, const QStyleOptionGraphicsItem *option,
QWidget *widget) override
{
//画一个圆角矩形
painter->drawRoundedRect(-10, -10, 20, 20, 5, 5);
}
};
boundingRect() 函数有许多不同的用途。QGraphicsScene其项目索引基于boundingRect(),QGraphicsView使用它来剔除不可见的项目,并在绘制重叠项目时确定需要重新构图的区域。
此外,QGraphicsItem的冲突检测机制使用boundingRect()提供有效的截止。碰撞检测 collidesWithItem()中的细粒度碰撞算法是基于调用 shape(),它返回项目形状的准确轮廓作为QPainterPath。
QGraphicsScene期望所有项目的boundingRect()和 shape()保持不变。如果要以任何方式更改项的几何形状,必须首先调用 prepareGeometryChange() ,以允许QGraphicsScene来更新它的簿记。
碰撞检测可以通过两种方式进行:
1.重新实现shape() 为您的项目返回一个准确的形状,并依赖于collidesWithItem() 进行“形状-形状”相交。如果形状很复杂,这可能是相当“昂贵”的。
2.重新实现 collidesWithItem() ,以提供您自己自定义的项目和形状碰撞算法。
可以调用 contains() 函数来确定该项是否包含一个点。这个功能也可以通过项目重新实现。contains() 的默认行为是基于调用 shape()的。
项目可以包含其他项目,也可以由其他项目包含。所有项目都可以有一个父项和一个子项列表。除非项目没有父坐标,否则其位置在父坐标中(即[]e。,父坐标的局部坐标)。父项将它们的位置和转换传播到所有子项。
项目可以包含其他项目,也可以被其他项目包含。所有项目都可以有一个父项目和一个子项目列表。除非该项没有父项,否则它的位置在父坐标中(即父节点的本地坐标)。父项目将它们的位置和变换传播给所有子项目。
转换
除了基本位置之外,QGraphicsItem还支持投影变换,刷卡机pos() 有几种方法可以更改项目的变换。对于简单的转换,您可以调用其中一个便利函数setRotation()或setScale(),或者您可以将任何转换矩阵传递给setTransform(),对于高级转换控制,您还可以选择通过调用setTransformations()。
项变换从父项到子项累积,因此如果父项和子项都旋转90度,子项的总变换将为180度。同样,如果该项的父项缩放到其原始大小的两倍,则其子项也将是原来的两倍。项目的变换不影响其自身的局部几何形状;所有几何函数(例如:包含包含 contains(), update() 和所有映射函数)仍然在本地坐标中操作。为了方便起见,QGraphicsItem提供了函数场景转换sceneTransform(),它返回该项的总变换矩阵(包括其位置以及所有父项的位置和变换),以及 scenePos(),它返回其在场景坐标中的位置。若要重置项目的矩阵,请调用resetTransform()。
根据应用的顺序,某些转换操作会产生不同的结果。例如,如果缩放一个变换,然后旋转它,可能会得到与先旋转变换不同的结果。但是,您在QGraphicsItem上设置转换属性的顺序不会影响结果转换;QGraphicsItem始终以固定的定义顺序应用属性:
- 应用该项的基础变换 (transform())
- 项目的转换列表按顺序应用 (transformations())
- 该项相对于其变换原点旋转 (rotation(), transformOriginPoint())
- 该项相对于其变换原点进行缩放(scale(), transformOriginPoint())
绘画
paint由paint() 函数调用QGraphicsView绘制项目的内容。该项目没有自己的背景或默认填充;项目后面的任何内容都将通过该函数中未明确绘制的所有区域发出。你可以通过update() 重画,可以选择传递需要重画的矩形。根据项目在视图中是否可见,项目可能会也可能不会被重新绘制;没有等同于QWidget::repaint() 。
项目由视图绘制,从父项目开始,然后按升序堆叠顺序绘制子项目。您可以通过调用来设置项的堆叠顺序setZValue(),并通过调用zValue(),具有低z值的项目在具有高z值的项目之前绘制。堆叠顺序适用于同级项目;父母总是比孩子先被引入。
整理
所有项目都以定义的稳定顺序绘制,该顺序决定了当您在场景中单击时哪些项目将首先接收鼠标输入。通常你不必担心排序问题,因为项目遵循“自然顺序”,遵循场景的逻辑结构。
项的子项堆叠在父项的顶部,同级项按插入顺序堆叠(即,按添加到场景中或添加到同一父项的相同顺序)。如果您先添加A项,然后添加B项,那么B项将位于A项之上。如果您随后添加C项,则这些项的堆叠顺序将是A项,B项,C项。
此示例显示了中机器人所有肢体的堆叠顺序(QT拖放机器人实例)举例。躯干是根项目(所有其他项目都是躯干的子项目或后代),因此首先绘制它。接下来,绘制头部,因为它是躯干子列表中的第一个项目。然后画左上手臂。由于下手臂是上臂的子手臂,因此将绘制下手臂,然后绘制上臂的下一个兄弟手臂,即上臂的右手臂,依此类推。
对于高级用户,有多种方法可以改变项目的排序方式:
- 你可以通过setZValue() 将其显式堆叠在其他同级项的顶部或下方。项目的默认Z值为0。具有相同Z值的项目按插入顺序堆叠。
- 你可以 stackBefore()对子列表重新排序。这将直接修改插入顺序。
- 您可以设置ItemStacksBehindParent 将子项堆叠在其父项后面。
两个同级项目的堆叠顺序也影响每个项目各自的子项目。因此,如果一个项目在另一个项目之上,那么它的所有子项目也将在其他项目的所有子项目之上。
事件
QGraphicsItem 通过 sceneEvent()函数将常见事件分配给一组方便的事件处理程序:
- contextMenuEvent() 处理上下文菜单事件
- 焦点事件()和focusOutEvent() 处理焦点进出事件
- hoverEnterEvent(), hoverMoveEvent()和 hoverLeaveEvent() 处理悬停输入、移动和离开事件
- inputMethodEvent() 处理输入事件,以支持辅助功能
- keyPressEvent() and keyReleaseEvent() 处理按键按压和释放事件
- mousePressEvent(), mouseMoveEvent(), mouseReleaseEvent() 和 mouseDoubleClickEvent() 处理鼠标按下、移动、释放、单击和双击事件
您可以通过安装事件过滤器来过滤任何其他项的事件。该功能于Qt的常规事件过滤不同(参见QObject::installEventFilter()),它只作用于QObject的子类。通过调用installSceneEventFilter()将您的项安装为另一个项的事件过滤器,过滤后的事件将由虚函数sceneEventFilter()接收,您可以通过调用removeSceneEventFilter()来移除项目事件过滤器。
自定义数据
有时,向项目注册自定义数据很有用,无论是自定义项还是标准项。你可以调用 setData() 来使用键-值对(键是整数,值是QVariant)在其中存储数据。若要从项中获取自定义数据,请调用 data(),Qt本身完全没有触及这一功能,它是专为了方便用户提供的。
See also QGraphicsScene, QGraphicsView, and Graphics View Framework.