qt - Qt 的 QGraphicsItem : How is this *supposed* to work? 中的事件和信号

标签 qt qt4 pyqt4

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

(A) 天真的方法 - 信令

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

实现:由于我不完全理解的原因,QGraphicsItems 不能发出() 信号。 It has been suggested也从 QGraphicsObject 继承的派生类可能能够解决这个问题。不过,在我看来,在 QGraphicsItems 上排除 emit() 可能是 Qt 开发人员的有意设计决定,因此,多重继承可能不是正确的解决方案。

(B) 容器级事件处理

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

实现: QGraphicsScene 绝对有能力处理否则会导致 QGraphicsItems 的事件。 QGraphicsScene 还提供了 itemsAt() 方法来确定其中的哪些东西受到位置事件的影响,比如鼠标点击。尽管如此,在容器类中为容器之间的协调 Action 构建相当多的逻辑感觉就像是未能正确封装。不好的做法?也许吧,但这似乎是它至少在 one official example 中的做法。 .

问题

  • 这里的正确解决方案是什么?如果不是A或B,那是不是我没有想到的其他东西?
  • 为什么 Qt 开发人员允许 QGraphicsItems 接收事件但不发送信号?这似乎是整个框架使用的设计模式的一个主要异常(exception)。
  • 这个问题的一个扩展是 QGraphicsItems 和高阶容器类之间的通信,如主应用程序。这意味着如何解决?
  • 最佳答案

    信令不是 QGraphicItem 的一部分,因为它们不是从 QObjects 继承的。这是出于性能原因的设计决定,以允许非常大和快速的场景。如果您决定确实需要信号的特殊情况,则创建 QGraphicsWidget 来填补这一空白。它确实从 QObject 继承,并允许您混合使用 QWidget 和 QGraphicsItem 功能。尽管如果您的场景大小适中,建议您避免这种情况。

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

    通常,尽管您应该利用场景来协调其对象。这已经是用于事件的模式(协调所有事件到项目的交付的场景)。

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

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

    您的具体情况是一个带有“热角”的矩形。我会认为这是一个自定义的 QGraphicsItem。您可能会将 QGraphicsRectItem 子类化,然后将其中的子热角项组合为子项( setParentItem() )。现在您的矩形项目知道它的子项并且可以直接对它们进行操作。您可以将矩形项设置为子项的 sceneEventFilter 并直接处理它们的事件。无需回到现场。让所有这些逻辑活在类里面。

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

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

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

  • 这些只是一些建议。我确定还有其他方法。

    关于qt - Qt 的 QGraphicsItem : How is this *supposed* to work? 中的事件和信号,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10590881/

    相关文章:

    c++ - Qt Release DLL错误

    c++ - 不明白为什么我不能在 QMainWindow 子类中调用 setCentralWidget

    python - 在布局中移动小部件 pyqt

    python - 如何过滤Qtableview中的多列?

    python - 为什么 QtGui.QSound 根本不播放任何东西?

    c++ - Qt 自定义控件大小

    qt - QML 组件枚举类属性

    qt - 获取客户电话号码

    c++ - 检查/确定 QString 是否包含 html

    c++ - 扩展 Qt 标准图标