让通知成为原始场景的一部分的幼稚解决方案是不好的——它破坏了模型-视图的分离。您可以有多个视图,所有视图都显示一个场景,但通常只有其中一个可以根据需要显示通知。
另一种简单的方法是在视图顶部覆盖 QWidget 通知。问题在于,在某些架构上,将常规 QWidgets 覆盖在加速 QGLWidgets 之上会使前者消失。请注意,QGraphicsView 的视口可能是 QGLWidget!
因此,唯一可移植的解决方案是在 QGraphicsSceneView 中的所有其他内容之上显式地进行绘画viewport()
。
下面是一个完整的例子。
// main.cpp
#include <QApplication>
#include <QGraphicsScene>
#include <QGraphicsView>
#include <QGraphicsItem>
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<QRectF>)), 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(¬ification);
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(QString::number(time++));
}
};
int main(int argc, char ** argv)
{
QApplication a(argc, argv);
Window window;
window.show();
a.exec();
}
#include "main.moc"