Qt的QGraphicsItem中的事件和信号:这**应该如何工作?

Bri*_*ion 11 qt qt4 pyqt4

与Qt中的其他原语一样,QGraphicsItems可以处理鼠标事件等.甜!现在说我需要将一个QGraphicsItem上的事件传播到同一场景中的其他QGraphicsItems.我可以想到两种方法可以解决这个问题:


(A)天真的方法 - 信号

概念:将兄弟QGraphicsItems与信号连接在一起.QGraphicsItem上的事件处理程序调用emit(),以唤起对其他QGraphicItem的协调响应.这遵循整个Qt框架中建立的一般设计模式.

实现:由于我没有完全掌握的原因,QGraphicsItems不能发出()信号.有人建议,也可以从QGraphicsObject继承的派生类可以解决这个问题.在我看来,在QGraphicsItems上排除emit()可能是Qt开发人员的有意设计决策,因此,多重继承可能不是正确的解决方案.

(B)容器级事件处理

概念: QGraphicsItems始终存在于QGraphicsScene类型的容器的上下文中.(A)中的事件在QGraphicsItem级别处理,而是由继承自QGraphicsScene的对象处理.该对象还实现了用于协调兄弟QGraphicsItem之间响应的逻辑.

实现: QGraphicsScene绝对有能力处理事件,否则将导致QGraphicsItems.QGraphicsScene还提供itemsAt()方法,用于确定其中的哪些内容受位置事件影响,如鼠标单击.尽管如此,在容器类中建立相当大的逻辑以便在容器之间进行协调操作,这感觉就像是无法正确封装.不好的做法?也许,但这似乎是至少在一个官方例子中完成的方式.


问题

  1. 什么是正确的解决方案?如果不是A或B,那么它是否是我没有想到的其他东西?
  2. 为什么Qt devs允许QGraphicsItems接收事件但不发送信号?这似乎是整个框架中使用的设计模式的一个主要例外.
  3. 此问题的扩展是QGraphicsItems和高阶容器类之间的通信,如主应用程序.这意味着如何解决?

jdi*_*jdi 8

信令不是QGraphicItem的一部分,因为它们不从QObjects继承.出于性能原因,这是一个设计决策,允许非常大而快的场景.如果你确定你真的需要信号的特殊情况,那么创建QGraphicsWidget来填补这个空白.它确实继承自QObject,让您可以混合使用QWidget和QGraphicsItem功能.虽然如果您的场景甚至相当大,建议您避免这种情况.

可能与您的情况相关的另一个选项是使用sceneEventFilter方法.您可以设置一个项目来接收另一个项目,并决定是否应该传播它们:http: //www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qgraphicsitem.html#sceneEventFilter
可以设置一个项目作为多个对象的过滤器.它可以识别每个单独的项目和事件以响应.

通常,您应该利用场景来协调其对象.这已经是用于事件的模式(协调将所有事件传递到项目的场景).

此外,似乎您的选项A是不可能的,因为QGraphicsItem甚至没有emit方法.您需要在其中组成一个QObject实例作为成员并使用它来发出信号.有点像myItem.qobject.emit().否则,您必须从QGraphicsObject继承自己的完全自定义的一个

更新1:解决主要评论更新

您的具体情况是一个带有"热角"的矩形.我会看到这是一个自定义的QGraphicsItem.您可能会将QGraphicsRectItem子类化,然后将子热门项目组合为子项目(setParentItem()).现在您的矩形项目了解其子项并可以直接对其进行操作.您可以将矩形项设置为子项的sceneEventFilter并直接处理它们的事件.无需回到现场.让所有这些逻辑都存在于课堂上.

更新2:解决您添加的问题#3

将通信之外的通信传播到QWidget有几种我能想到的方法:

  1. 在这种情况下,您可以考虑是否要使用QGraphicsObject子类作为根项,然后将其余对象组合为子项(rect,然后将热点作为rect的子项).这将允许对象发出信号.为清楚起见,它们可能仍然连接到场景,然后场景的高阶容器将连接到场景.您必须根据具体情况选择此方法,具体取决于场景的复杂程度以及QGraphicsObject是否对其产生任何性能影响.如果你有大量的这些实例,你应该避免这种情况.
  2. 您可以为rect类定义一个回调,场景可以为其设置.要么像:graphicsRect.resizedCallback作为属性,要么是设置者graphicsRect.setResizedCallback(cbk).在你的rect类中,你只需在适当的时候调用它.如果它设置了回调,它可以用来直接调用场景中的某些内容.rect类仍然不知道该逻辑.它只是调用一个回调.

这些只是一些建议.我相信还有其他方法.