Qt Graphics View Framework-ダークサイド。 パート2

私たちの旅を始めたので 、私たちは止まらず、文書の暗い側面を研究し続けます。 どこかでそれらはQt全体の特徴であるかもしれませんが、どこかではグラフィックビューのみが固有です。 しかし、何らかの方法で、彼らとの会談が常に苦痛を伴うとは限りません。



ケース番号3



次のコードを書く例として、アイテムを書きたい

MainWindow.h
class MainWindow : public QWidget { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: QGraphicsScene *m_scene; QGraphicsRectItem *m_rect; QGraphicsItem *m_cross; QGraphicsView * graphicsView; };
      
      





MainWindow.cpp
 class CrossItem: public QGraphicsItem { public: QRectF boundingRect() const { return QRectF(0, 0, 30*scale(), 30*scale()); } void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option) Q_UNUSED(widget); painter->setPen(QColor(Qt::red)); painter->drawLine(10, 0, 20, 0); painter->drawLine(20*scale(), 0*scale(), 20*scale(), 10*scale()); painter->drawLine(20, 10, 30, 10); painter->drawLine(30, 10, 30, 20); painter->drawLine(30, 20, 20, 20); painter->drawLine(20, 20, 20, 30); painter->drawLine(20, 30, 10, 30); painter->drawLine(10, 30, 10, 20); painter->drawLine(10, 20, 0, 20); painter->drawLine( 0, 20, 0, 10); painter->drawLine( 0, 10, 10, 10); painter->drawLine(10, 10, 10, 0); } }; MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { setLayout(new QGridLayout()); graphicsView = new QGraphicsView(); layout()->addWidget(graphicsView); graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_scene = new QGraphicsScene(); m_cross = new CrossItem(); m_scene->addItem(m_cross); // m_cross->setScale(2); m_rect = new QGraphicsRectItem(m_cross->boundingRect(), m_cross); m_scene->addItem(m_rect); m_scene->setSceneRect(m_rect->boundingRect()); graphicsView->setScene(m_scene); } MainWindow::~MainWindow() { }
      
      





コンパイル、実行、十字架に刻まれた正方形を参照してください。 行のコメントを解除し、プロジェクトを再構築して、起動後にすべてのエラーが表示されるようにします。

事実は次のとおりです。

 painter->drawLine(20*scale(), 0*scale(), 20*scale(), 10*scale());
      
      





そして

 return QRectF(0, 0, 30*scale(), 30*scale());
      
      





-心からの悲しみ。



QGraphicsItemが変換データを保存する方法を見てみましょう。



 struct QGraphicsItemPrivate::TransformData { QTransform transform; qreal scale; qreal rotation; qreal xOrigin; qreal yOrigin; QList<QGraphicsTransform *> graphicsTransforms; bool onlyTransform; TransformData() : scale(1.0), rotation(0.0), xOrigin(0.0), yOrigin(0.0), onlyTransform(true) { } QTransform computedFullTransform(QTransform *postmultiplyTransform = 0) const { if (onlyTransform) { if (!postmultiplyTransform || postmultiplyTransform->isIdentity()) return transform; if (transform.isIdentity()) return *postmultiplyTransform; return transform * *postmultiplyTransform; } QTransform x(transform); if (!graphicsTransforms.isEmpty()) { QMatrix4x4 m; for (int i = 0; i < graphicsTransforms.size(); ++i) graphicsTransforms.at(i)->applyTo(&m); x *= m.toTransform(); } x.translate(xOrigin, yOrigin); x.rotate(rotation); x.scale(scale, scale); x.translate(-xOrigin, -yOrigin); if (postmultiplyTransform) x *= *postmultiplyTransform; return x; } };
      
      





そして、実際には、シーンを描画する前に、computeFullTransformメソッドを取得し、さらにいくつかのシャーマニックアクションを実行した後、QPainterにパームします。 ここで、アイテムの形状をトリッキーにしたい場合は、メソッドsetScalesetPossetRotation 、およびsetTransformsを使用する必要があり、他には何も必要ないことに注意してください。



事例番号4



アイテム上のマウスの動きを追跡したい。 すぐに警告します-熊手はすべてのステップで文字通りレイアウトされています。 そして彼らは私を非常に痛くて非常に激しく打ちました。 しかし、試練の完全なリストについては説明しません。 私はキーポイントにのみ専念します

Mainwindow.cppを次のように書き換えます。
 #include "MainWindow.h" #include <QGridLayout> #include <QGraphicsSceneHoverEvent> #include <QDebug> class MyRect: public QGraphicsRectItem { public: MyRect(const QRectF &rect, QGraphicsItem *parent=0):QGraphicsRectItem(rect, parent){} protected: void hoverMoveEvent(QGraphicsSceneHoverEvent *event) { qDebug()<<"rect"<<event->pos(); QGraphicsRectItem::hoverMoveEvent(event); } }; class CrossItem: public QGraphicsItem { public: QRectF boundingRect() const { return QRectF(0, 0, 30, 30); } void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) { Q_UNUSED(option) Q_UNUSED(widget); painter->setPen(QColor(Qt::red)); painter->drawLine(10, 0, 20, 0); painter->drawLine(20, 0, 20, 10); painter->drawLine(20, 10, 30, 10); painter->drawLine(30, 10, 30, 20); painter->drawLine(30, 20, 20, 20); painter->drawLine(20, 20, 20, 30); painter->drawLine(20, 30, 10, 30); painter->drawLine(10, 30, 10, 20); painter->drawLine(10, 20, 0, 20); painter->drawLine( 0, 20, 0, 10); painter->drawLine( 0, 10, 10, 10); painter->drawLine(10, 10, 10, 0); } protected: void hoverMoveEvent(QGraphicsSceneHoverEvent *event) { qDebug()<<"cross"<<event->pos(); QGraphicsItem::hoverMoveEvent(event); } }; MainWindow::MainWindow(QWidget *parent) : QWidget(parent) { setLayout(new QGridLayout()); graphicsView = new QGraphicsView(); layout()->addWidget(graphicsView); graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); m_scene = new QGraphicsScene(); m_cross = new CrossItem(); m_rect = new MyRect(m_cross->boundingRect(), m_cross); m_cross->setAcceptHoverEvents(true); m_rect->setAcceptHoverEvents(true); m_scene->addItem(m_cross); m_scene->setSceneRect(m_rect->boundingRect()); graphicsView->setScene(m_scene); } MainWindow::~MainWindow() { }
      
      





シーンイベントは通常のイベントの完全な類似物であるという一般的な論理に従います。 QGraphicsSceneHoverEventでドックに喜んで報告していることは何ですか。



コンパイルして実行すると、マウスを動かしたときにイベントが長方形にしか到達しないことがわかります。 原始的なsetAcceptHoverEventsメソッドを説明するときに、ドックおよびマージンのどこかに登ります。



親アイテムは、子供の前にホバーエンターイベントを受け取り、子供の後にイベントを離れます。 ただし、カーソルが子に入ると、親はホバー離脱イベントを受け取りません。 カーソルがその子の領域を含むその領域を離れるまで、親は「ホバリング」されたままです。



親アイテムが子イベントを処理する場合、カーソルがその子を通過するときにホバー移動、ドラッグ移動、およびドロップイベントを受け取りますが、ホバーエンターおよびホバーリーブは受け取りません。子供たち。



ウィンドウ装飾のあるQGraphicsWidgetは、acceptHoverEvents()の値に関係なくホバーイベントを受け入れます。


そのため、子孫のイベントを追跡する必要があります。 これを実現し、他のことを考慮して、私たちは私たちを助ける方法を探しています。 そして、これはsetFiltersChildEventsです (同様のsetHandlesChildEventsと混同しないでください。そのような栄光はありません)。 コンストラクターに追加します。

 m_cross->setFiltersChildEvents(true);
      
      





また、CrossItemクラスにフィルターを追加します。

  bool sceneEventFilter(QGraphicsItem *watched, QEvent *event) { if(event->type() == QEvent::GraphicsSceneHoverMove) qDebug()<<"cross"<<event; return false; }
      
      





コンパイルして実行します。 やった! 獲得した!!!



まとめ



残念ながら、前の記事のように建設的な結果を引き出すために、私は今のところ成功しません。 むしろ、それは戸惑いです-幾何学的変換からのアイテムの独立にかなりの努力を費やしたため、Qt開発者はイベントをアイテムに配信するための非常に奇妙なシステムを提供しました。 上記の例は例外的なケースである可能性が高いですがQGraphicsItemのフラグを見るだけで十分に考えることができます。



All Articles