Important: Please read the Qt Code of Conduct -

QGraphicsView efficient offscreen painting

  • Hello! My problem is following: I want a QGraphicsView to be rendered offscreen (say on QImage), and with minimum update rect as it is done by default.
    Before that I've already acheived full offscreen render: when QGraphicsScene::changed(QRectF) I would redraw through all the size (it takes ~100 ms). Now I want to only redraw a minimum rect, but the changed(QRectF) does not allow that, it always fires the maximum size rect.
    So I started to investigate Paint events of QGraphicsView::viewport(). However, there is no Paint events for invisible widgets, and my widgets of course are invisible as I render offscreen. But Paint event was so tempting with its QPaintEvent::rect(), that I even enabled visibility of actual widget for the moment. And it helped: as soon as widget had its own window it started to have all the Paint events and I got the render as required.

    Now the question is: how do I hide the actual widget, and still have its Paint events all the way?

    Event filter is capturing QPaintEvents for viewport. I try to make use of Qt::WA_DontShowOnScreen flag, with no success yet. As soon as actual widget is invisible I have no Paint events on mouse hovering the buttons, new widgets addition etc.

    P.S. I also consider use of the changed() signal if I can get minimal rect from there somehow.

    Here some codes attached:
    @mWidgetScene = new QGraphicsScene(this);
    mWidgetView = new QGraphicsView(mWidgetScene);
    mWidgetView->setAlignment(Qt::AlignLeft | Qt::AlignTop);
    //mWidgetView->setAttribute(Qt::WA_DontShowOnScreen); // comment to get it drawing

    // tried this too

    // somewhat scene activation for invisible cases
    //QEvent wsce(QEvent::WindowActivate);
    //QApplication::sendEvent(mWidgetScene, &wsce);@

    Event filter
    @bool UiManager::eventFilter(QObject *target, QEvent *event) {
    if (target == mWidgetView->viewport() && event->type() == QEvent::Paint) {

    QPaintEvent pe = (QPaintEvent)event;

    if(!mUiDirty) {
    redrawRect = pe->rect();
    mUiDirty = true;
    redrawRect = redrawRect.united(pe->rect());
    qDebug() << "paint" << pe->rect() << "->" << redrawRect;

    // can't return true now, it breaks drawing again somehow
    // return true;

    return false;

    Rendering is obvious
    @mWidgetView->render(&painter, redrawRect, redrawRect);@

Log in to reply