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

最初の記事では、フレームワークの利点についてどうすればよいかについて話しました。 今日は、文書化されていない暗い側面についてお話します。

事例番号1


表示されているウィンドウのサイズに応じて、シーンとその中のオブジェクトのサイズを変更します。 ドックは、「QGraphicsViewはビューポートウィジェットの所有権を取得します」と述べています。 さて、最も簡単なプロジェクトを作成して、次のように書きましょう。

MainWindow.h:
#ifndef MAINWINDOW_H #define MAINWINDOW_H #include <QMainWindow> #include <QGraphicsScene> #include <QGraphicsEllipseItem> #include <QGraphicsView> class MainWindow : public QWidget { Q_OBJECT public: explicit MainWindow(QWidget *parent = 0); ~MainWindow(); private: bool eventFilter(QObject *, QEvent *); private: QGraphicsScene *m_scene; QGraphicsEllipseItem *m_elipse; QGraphicsView * graphicsView; }; #endif // MAINWINDOW_H 

MainWindow.cpp:
 #include "MainWindow.h" #include <QGridLayout> #include <QEvent> #include <QResizeEvent> 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_elipse = new QGraphicsEllipseItem(); m_scene->addItem(m_elipse); m_scene->setSceneRect(m_elipse->boundingRect()); graphicsView->setScene(m_scene); graphicsView->installEventFilter(this); } MainWindow::~MainWindow() { } bool MainWindow::eventFilter(QObject *, QEvent *event) { if(event->type() == QEvent::Resize ) { QResizeEvent *res = reinterpret_cast<QResizeEvent*>(event); m_elipse->setRect(0, 0, res->size().width(), res->size().height()); return true; } return false; } 

ウィジェットのサイズを変更することにより、楕円のサイズを変更することが期待されますが、 領域のサイズ変更と表示。 コンパイルして実行し、正常に機能しないことを確認します。初期サイズを小さくすることはできますが、それを超えると楕円が切り取られます。

次に変更

  graphicsView->installEventFilter(this); 


  graphicsView->viewport()->installEventFilter(this); 


コンパイル、実行-すべてが機能します。 次に、シーンにフィルターを設定してみましょう。 コンパイルして実行しますが、何も表示されません。

ケース番号2


マウスがシーン内を移動するときのマウスの位置を追跡します。 このため、テストとクラスを次のように変更します。
 bool MainWindow::eventFilter(QObject *, QEvent *event) { if(event->type() ==QEvent::MouseMove) { qDebug()<<event; return true; } return false; } 


コンストラクターに追加します。
 graphicsView->setMouseTracking(true); 


フィルターをgraphicsViewにインストールします。
コンパイル、実行、動作しないことを確認します。 ビューポートにフィルターをインストールすると、すべてが再び機能します。
次に、少し変更します。

  if(event->type() ==QEvent::MouseMove) 

に置き換える
  if(event->type() ==QEvent::GraphicsSceneMouseMove) 


そして、シーンにフィルターをインストールします。 前回とは異なり、マウスの動きが追跡されていることがわかります。

調査の結論


初心者の観点からは奇妙なことではありませんが、グラフィックスフレームワークは、ロジックを個別に表示し、個別に構成するというロジックに従います。 したがって、サイズ変更イベントはシーンに送信されません。 そして、graphicsViewはビューポートを本当に愛用しています。 ケース1でフィルターを次のものに置き換えた場合、これを確認できます。

  if(event->type() == QEvent::Resize ) { QResizeEvent *res = reinterpret_cast<QResizeEvent*>(event); m_elipse->setRect(0, 0, res->size().width(), res->size().height()); } return false; 

つまり イベントのフィルタリングを削除すると、予想される動作が表示されます。 つまり イベントは除外され、それ以上ビューポートに送信されませんでした。 ただし、適切な削減動作は、コードで呼び出されるQtの内部ロジックまたは自発的なイベントによって引き起こされます。

イベントのシーンへの転送に戻ります。 このプロセスはまったく説明されていませんが、重要なポイントがあります:シーンに進む前に、graphicsViewはイベントを対応するQGRaphisSceneEventに変換しますが、これは既に特殊なメソッドで発生するため、エントリポイント( eventまたはviewportEventではなく、ドックでオーバーライドすることをお勧めします)

繰り返しになりますが、最後の瞬間に注意を払います。フレームワークのロジックは、すべての外部イベントがシーンで動作するように準備されるようなものです。 つまり シーンに渡す必要のあるQEventがある場合、Qtのロジックに違反しない最良の方法は、QGRaphicsSceneEventから継承したカスタムイベントのアナログを作成し、変換してQGraphicsViewから継承したクラスで呼び出されるシーンに送信するメソッドを記述することです、よく、この最も変更されたQGraphicsViewにQEventを送信します。

最後の段階であるItem-sへのイベント配信を検討する必要があります。 ここで、画像はシーンへの配信と似ています。つまり、イベントが到着した後、どの特殊な機能を使用するかが決定されます。 この特殊な機能では、メソッドitemAt()を使用してイベントの座標が決定され、イベントを配信するアイテムが決定されます。その後、イベントはアイテムへの配信の準備ができてから送信されます。

ところで、熊手もあります。 ドックは、幾何学的な寸法を変更する前に、geometryChangeを呼び出す必要があると言います。そうしないと、レンダリングで問題が発生します。 しかし、イベント配信に関して問題が発生するだけではありません。

Source: https://habr.com/ru/post/J182614/


All Articles