Dessine un élément dans un emplacement statique par rapport à QGraphicsView

Je voudrais dessiner une notification qui apparaît toujours dans le coin supérieur droit de mon QGraphicsView . Cependant, les positions de QGraphicsItems sont spécifiées en coordonnées de scène. Par conséquent, si l’utilisateur effectuait un panoramique / un zoom pour afficher une autre partie de la scène, cette notification disparaîtrait de l’écran.

J’ai compris que je pouvais simuler ce comportement en déplaçant et en mettant à l’échelle la notification chaque fois que la vue en cours change. Mais cela semble terriblement inefficace et pas du tout élégant.

Il semble que QGraphicsView devrait supporter ce type de comportement. La documentation mentionne un indicateur ItemIsPanel qui semble optimiste, mais ne mentionne rien concernant le placement statique dans la vue. ItemIgnoresTransformations également à la réduction / zoom, mais pas au panoramique.

Existe-t-il une fonctionnalité Qt intégrée prenant en charge ce comportement?

La solution naïve consistant à faire en sorte que la notification fasse partie de la scène d’origine est mauvaise: elle brise la séparation modèle-vue. Vous pouvez avoir plusieurs vues, toutes montrant une scène, mais généralement, sur une seule d’entre elles, la notification peut apparaître comme vous le souhaitez.

Une autre méthode simple consiste à superposer une notification QWidget au-dessus de votre vue. Le problème est que, sur certaines architectures, la superposition de QWidgets classiques à celle de QGLWidgets accélérés fera disparaître le premier. Notez que la fenêtre d’affichage d’un QGraphicsView peut être un QGLWidget!

Ainsi, la seule solution portable consiste à faire explicitement la peinture par-dessus tout dans le viewport viewport() de QGraphicsSceneView.

Vous trouverez ci-dessous un exemple complet.

entrez la description de l'image ici

 // main.cpp #include  #include  #include  #include  qreal rnd() { return qrand() / (float)RAND_MAX; } class OverlaidGraphicsView : public QGraphicsView { Q_OBJECT QGraphicsScene * m_overlayScene; public: explicit OverlaidGraphicsView(QWidget* parent = 0) : QGraphicsView(parent), m_overlayScene(NULL) {} explicit OverlaidGraphicsView(QGraphicsScene * scene = 0, QWidget * parent = 0) : QGraphicsView(scene, parent), m_overlayScene(NULL) {} void setOverlayScene(QGraphicsScene * scene) { if (scene == m_overlayScene) return; m_overlayScene = scene; connect(scene, SIGNAL(changed(QList)), SLOT(overlayChanged())); update(); } QGraphicsScene * overlayScene() const { return m_overlayScene; } void paintEvent(QPaintEvent *ev) { QGraphicsView::paintEvent(ev); if (m_overlayScene) paintOverlay(); } virtual void paintOverlay() { QPainter p(viewport()); p.setRenderHints(renderHints()); m_overlayScene->render(&p, viewport()->rect()); } Q_SLOT void overlayChanged() { update(); } }; class Window : public QWidget { QGraphicsScene scene, notification; OverlaidGraphicsView * view; QGraphicsSimpleTextItem * item; int timerId; int time; public: Window() : view(new OverlaidGraphicsView(&scene, this)), timerId(-1), time(0) { for (int i = 0; i < 20; ++ i) { qreal w = rnd()*0.3, h = rnd()*0.3; scene.addEllipse(rnd()*(1-w), rnd()*(1-h), w, h, QPen(Qt::red), QBrush(Qt::lightGray)); } view->fitInView(0, 0, 1, 1); view->setResizeAnchor(QGraphicsView::AnchorViewCenter); view->setRenderHint(QPainter::Antialiasing); view->setOverlayScene(&notification); item = new QGraphicsSimpleTextItem(); item->setPen(QPen(Qt::blue)); item->setBrush(Qt::NoBrush); item->setPos(95, 0); notification.addItem(item); notification.addRect(0, 0, 100, 0, Qt::NoPen, Qt::NoBrush); // strut timerId = startTimer(1000); QTimerEvent ev(timerId); timerEvent(&ev); } void resizeEvent(QResizeEvent * ev) { view->resize(size()); view->fitInView(0, 0, 1, 1, Qt::KeepAspectRatio); QWidget::resizeEvent(ev); } void timerEvent(QTimerEvent * ev) { if (ev->timerId() != timerId) return; item->setText(QSsortingng::number(time++)); } }; int main(int argc, char ** argv) { QApplication a(argc, argv); Window window; window.show(); a.exec(); } #include "main.moc"