13

Qtの他のプリミティブと同様に、QGraphicsItemsはマウスイベントなどを処理できます。甘い!ここで、1つのQGraphicsItemのイベントを、同じシーン内の他のQGraphicsItemに伝播する必要があるとします。私はこれにアプローチするかもしれない2つの方法を考えることができます:


(A)素朴なアプローチ-シグナリング

コンセプト:兄弟のQGraphicsItemsをシグナルと接続します。QGraphicsItemのイベントハンドラーは、他のQGraphicItemsで調整された応答を呼び出すemit()を呼び出します。これは、Qtフレームワーク全体で確立された一般的なデザインパターンに従います。

実装:私が完全に理解していない理由により、QGraphicsItemsは()信号を発行できません。QGraphicsObjectからも継承する派生クラスがこれを回避できる可能性があることが示唆されています。ただし、QGraphicsItemsでのemit()の除外は、おそらくQt開発者の意図的な設計上の決定であり、したがって、多重継承はおそらく正しい解決策ではないように思われます。

(B)コンテナレベルのイベント処理

概念: QGraphicsItemsは、常にタイプQGraphicsSceneのコンテナーのコンテキストに存在します。(A)でQGraphicsItemのレベルで処理されたイベントは、代わりにQGraphicsSceneから継承したオブジェクトによって処理されます。このオブジェクトは、兄弟のQGraphicsItem間の応答を調整するためのロジックも実装します。

実装: QGraphicsSceneには、QGraphicsItemsに到達するイベントを確実に処理する機能があります。QGraphicsSceneは、マウスクリックなどの位置イベントの影響を受けるものを判別するためのitemsAt()メソッドも提供します。それでも、コンテナクラス内にかなりのロジックを構築して、被収容者間の調整されたアクションを実現することは、適切にカプセル化できないように感じます。悪い習慣?たぶん、しかしこれは少なくとも1つの公式の例で行われている方法のようです。


質問

  1. ここで正しい解決策は何ですか?AでもBでもないのなら、それは私が考えていなかった何か他のものですか?
  2. Qt開発者がQGraphicsItemsにイベントの受信を許可し、シグナルの送信を許可しないのはなぜですか?これは、フレームワーク全体で使用されるデザインパターンの主要な例外のようです。
  3. この問題の拡張は、QGraphicsItemsとメインアプリケーションのような高次コンテナクラスとの間の通信です。それはどのように対処されることを意味しますか?
4

2 に答える 2

9

シグナリングはQObjectsから継承しないため、QGraphicItemの一部ではありません。これは、非常に大きくて高速なシーンを可能にするための、パフォーマンス上の理由からの設計上の決定でした。シグナルの特殊なケースが本当に必要であると判断した場合は、このギャップを埋めるためにQGraphicsWidgetが作成されました。QObjectから継承し、QWidgetとQGraphicsItemの機能を組み合わせることができます。ただし、シーンが適度に大きい場合は、これを回避することをお勧めします。

状況に関連する可能性のある別のオプションは、sceneEventFilterメソッドを使用することです。あるアイテムを別のイベントを受信するように設定し、それらを伝播するかどうかを決定できます。http: //www.riverbankcomputing.co.uk/static/Docs/PyQt4/html/qgraphicsitem.html#sceneEventFilter1
つのアイテムを設定できます。複数のオブジェクトのフィルターとして。また、応答する個々のアイテムとイベントを識別できます。

一般的には、オブジェクト間の調整にシーンを利用する必要があります。それはすでにイベント(アイテムへのすべてのイベントの配信を調整するシーン)に使用されているパターンです。

また、QGraphicsItemにはemitメソッドさえないため、オプションAは使用できないようです。その中にメンバーとして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クラスはまだそのロジックの知識を持っていません。コールバックを呼び出すだけです。

これらはほんの一部の提案です。他にも方法があると思います。

于 2012-05-14T21:14:58.427 に答える
1

QGraphicsItemが比較的少ない場合を除いて、Bをお勧めします。QObjectsにはある程度のオーバーヘッドが伴うため、QGraphicsItemsはQObjectsではないと思います。QGraphicsViewフレームワークは、シーンへの多数(たとえば、数千)のQGraphicsItemの迅速な挿入と削除を可能にするように設計されているため、より軽量なアプローチが好まれました。

QGraphicsItemsの子育ての概念に目を向けます。QGraphicsItemsには親と子を含めることができ、これにはQObject間のペアレント化と同様のいくつかの効果があります。たとえば、親QGraphicsItemを移動すると、その子も一緒に移動し、親を削除すると、その子も削除されます。を使用してQGraphicsItemの親にアクセスし、を使用しQGraphicsItem::parentItem()て子にアクセスできますQGraphicsItem::childItems()。したがって、次のような兄弟アイテムに簡単にアクセスできます。

QList<QGraphicsItem *> mySiblings = this->parentItem()->childItems();

mySiblingsを含むことに注意してくださいthis

于 2012-05-14T21:05:39.817 に答える