Qt 的 QGraphicsItem 中的事件和信号:*应该*如何工作? [英] Events and signals in Qt's QGraphicsItem: How is this *supposed* to work?

查看:36
本文介绍了Qt 的 QGraphicsItem 中的事件和信号:*应该*如何工作?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Like other primitives in Qt, QGraphicsItems can handle mouse events and the like. Sweet! Now say I need for an event on one QGraphicsItem to be propagated to some other QGraphicsItems in the same scene. I can think of two ways that one might approach this:

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

Concept : Connect sibling QGraphicsItems together with signals. Event handlers on QGraphicsItem call emit()s that evoke coordinated responses on other QGraphicItems. This follows the general design pattern established throughout the Qt framework.

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

Implementation : For reasons that I do not fully grasp, QGraphicsItems cannot emit() signals. It has been suggested that derived classes that also inherit from QGraphicsObject may be able to work around this. It seems to me, though, that the exclusion of emit() on QGraphicsItems was probably an intentional design decision on the part of the Qt devs and, therefore, multiple inheritance is probably not the Right Solution.

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

Concept : QGraphicsItems always exist in the context of a container of type QGraphicsScene. Events that in (A) were handled at the level of the QGraphicsItem are instead handled by an object inheriting from QGraphicsScene. This object also implements the logic for coordinating responses between sibling QGraphicsItems.

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

Implementation : QGraphicsScene definitely has the ability to handle events that would otherwise make their way down to QGraphicsItems. QGraphicsScene also provides the itemsAt() method for determining which of the things in it are affected by positional events, like mouse clicks. Still, building up considerable logic within a container class for coordinated action among containees feels like a failure to encapsulate properly. Bad practice? Maybe, but this seems to be the way it's done in at least one official example.

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

推荐答案

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

Signaling is not part of QGraphicItem because they do not inherit from QObjects. This was a design decision for performance reasons, to allow very large and fast scenes. If you decide you really need special cases for signals, QGraphicsWidget was created to fill this gap. It does inherit from QObject and lets you have a mixture of QWidget and QGraphicsItem functionality. Though it is recommended that you avoid this if your scenes are even moderately sizable.

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

Another option which might be relevant to your situation is to make use of the sceneEventFilter method. You can set one item to receive events for another and decide if they should be propagated or not: http://www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qgraphicsitem.html#sceneEventFilter
One item can be set as the filter for multiple objects. And it can identify each individual item and event to respond to.

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

Generally though you should make use of the scene for coordination across its objects. That is already the pattern being used for events (the scene coordinating delivery of all events to the items).

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

Also, it seems that your option A is not possible because QGraphicsItem does not even have an emit method. You would need to compose a QObject instance inside it as a member and use that to emit signals. Something along the lines of myItem.qobject.emit(). Otherwise, you would have to inherit your own completely custom one from QGraphicsObject

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

Update 1: Addressing your main comment update

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

Your specific situation is a rectangle with "hot corners". I would see this being a custom QGraphicsItem. You would probably subclass QGraphicsRectItem, and then compose the child hot corner items inside as children items (setParentItem()). Now your rectangle item knows about its children and can act on them directly. You could set the rectangle item to be the sceneEventFilter for the children and handle their events directly. No need to go back up to the scene. Let all this logic live in the class.

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

Update 2: Addressing your added question #3

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

Propagating communications up beyond the scene to QWidget's has a couple approaches I can think of:

  1. 在这种情况下,您可以考虑是否要使用 QGraphicsObject 子类作为根项,然后将其余对象组合为子项(矩形,然后将热角作为矩形的子项).这将允许对象发出信号.为清楚起见,它们可能仍会连接到场景,然后场景的高阶容器将连接到场景.您必须根据场景的复杂性以及 QGraphicsObject 是否对其性能有任何影响,根据具体情况选择这种方法.如果您将拥有大量此类实例,您可能应该避免这种情况.
  2. 您可以为您的 rect 类定义一个回调,可以为其设置场景.类似于:graphicsRect.resizedCallback 作为属性,或 setter graphicsRect.setResizedCallback(cbk).在您的 rect 类中,您只需在适当的时候调用它.如果它设置了回调,它可用于直接调用场景中的某些内容.rect 类仍然不知道该逻辑.它只是调用回调.
  1. This is a situation where you can consider if you want to use a QGraphicsObject subclass as your root item, and then compose the rest of your objects as children (the rect, then the hot corners as children of the rect). This would allow the object to emit signals. For clarity they would probably still be connected to the scene, and then the higher order container of the scene would connect to the scene. You would have to choose this approach on a case by case, depending on the complexity of your scene and whether the QGraphicsObject has any performance impact on it. You should probably avoid this if you will have a great number of these instances.
  2. You could define a callback for your rect class, for which the scene can set. Either something like: graphicsRect.resizedCallback as an attribute, or a setter graphicsRect.setResizedCallback(cbk). In your rect class, you would just call that when appropriate. If the callback it set, it can be used to call something on your scene directly. The rect class still has no knowledge of that logic. It just calls a callback.

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

Those are just some suggestions. I'm sure there are other ways.

这篇关于Qt 的 QGraphicsItem 中的事件和信号:*应该*如何工作?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆