david
david

Reputation: 633

Unwanted margin inside QGraphicsView with Scrollbars

I am developing a video player, using a QGraphicsView to display the video. The QGraphicsView is displaying a QGraphicsScene with a single QGraphicsPixmapItem which contains the current video frame. The background of the view is black.

As long as the frame is smaller than the view, everything is alright, the video frame is displayed in the center of the view and the rest of the view is black. When the view has the same size as the frame, only the frame is shown, (obviously) no background. When the video frame is greater than the view, scrollbars are shown so the user can scroll to see the other parts of the frame.

The problem: When the scrollbars are shown, it is possible to scroll past the video frame. There is a margin of 8 pixels on the bottom and on the right where the background is visible. If the video frame is greater than the view, there should be no background visible and it should not be possible to scroll past the video frame.

I reduced the problem to a short source code that demonstrates the problem, showing a 200x200 px red QPixmap in a QGraphicsView with green background.

#include <QtGui/QApplication>
#include <QMainWindow>
#include <QGraphicsScene>
#include <QGraphicsView>

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    QMainWindow window;

    QPixmap pixmap(200, 200);
    pixmap.fill(QColor(255, 0, 0));

    QGraphicsScene scene(&window);
    scene.addPixmap(pixmap);

    QGraphicsView view(&window);
    view.setBackgroundBrush(QColor(0, 255, 0));
    view.setScene(&scene);

    window.setCentralWidget(&view);
    window.show();
    window.resize(199, 199);

    return app.exec();
}

I've also made an image of the problem (the black border isn't included in the example code): https://i.sstatic.net/K6I3R.jpg

On the left window, the QGraphicsView has the same size as the rectangle, on the right window it is a little bit smaller, so scrollbars are shown. And also the background is visible (it should not be visible).

I already tried setting the sceneRect and various other attributes of QWidget, QGraphicsView and QGraphicsScene but found nothing that changed anything with the problem.

I also tried running the example problem in a virtual machine to exclude the possibility that my Qt/KDE version has a bug.

I have no idea why the background is suddenly shown when there are scrollbars. How can I get rid of that? If that is not possible, do you have an idea how I could work around that?

Thanks in advance.

Upvotes: 5

Views: 3323

Answers (5)

user136036
user136036

Reputation: 12364

Problem is a bug with QGraphicsView::fitInView() they don't care about: https://bugreports.qt.io/browse/QTBUG-11945

Instead of reimplementing your own fitInView, just remove the margins from the view when you create it.

view.setViewportMargins(-2, -2, -2, -2)
view.setFrameStyle(QFrame.NoFrame)

Upvotes: 6

Adriel Jr
Adriel Jr

Reputation: 2681

I fixed it creating my own fitInView() method. It is basically the same as the original QGraphicView method, except for the margins:

void MyClass::fitInView_fixed(const QRectF &rect, Qt::AspectRatioMode aspectRatioMode)
{
    if (!scene() || rect.isNull())
        return;
    auto unity = transform().mapRect(QRectF(0, 0, 1, 1));
    if (unity.isEmpty())
        return;
    scale(1/unity.width(), 1/unity.height());
    auto viewRect = viewport()->rect();
    if (viewRect.isEmpty())
        return;
    auto sceneRect = transform().mapRect(rect);
    if (sceneRect.isEmpty())
        return;
    qreal xratio = viewRect.width() / sceneRect.width();
    qreal yratio = viewRect.height() / sceneRect.height();

    // Respect the aspect ratio mode.
    switch (aspectRatioMode) {
    case Qt::KeepAspectRatio:
        xratio = yratio = qMin(xratio, yratio);
        break;
    case Qt::KeepAspectRatioByExpanding:
        xratio = yratio = qMax(xratio, yratio);
        break;
    case Qt::IgnoreAspectRatio:
        break;
    }
    scale(xratio, yratio);
    centerOn(rect.center());
}

Upvotes: 1

Jason Newton
Jason Newton

Reputation: 1211

This is really just this question in disguise - take a look and vote on https://bugreports.qt.io/browse/QTBUG-42331

In short, fitInView has hardcoded margins and this can cause all kinds of havoc - the least of which is that now you lose a few pixels of display area and might also force unnecessary rescaling.

ps. Make sure to select an answer

Upvotes: 1

NoDataDumpNoContribution
NoDataDumpNoContribution

Reputation: 10865

I tried the snippet from the question but under Python using the PySide wrapper around Qt. The code is almost identical.

import sys
from PySide import QtGui

if __name__ == "__main__":
    app = QtGui.QApplication(sys.argv)
    window = QtGui.QMainWindow()

    pixmap = QtGui.QPixmap(200, 200)
    pixmap.fill(QtGui.QColor(255, 0, 0))

    scene = QtGui.QGraphicsScene(window)
    scene.addPixmap(pixmap)

    view = QtGui.QGraphicsView(window)
    view.setBackgroundBrush(QtGui.QColor(0, 255, 0))
    view.setScene(scene)

    window.setCentralWidget(view)
    window.show()
    window.resize(199, 199)

    sys.exit(app.exec_())

The scroll bars appear but I don't see any green area!

I guess since it is only a wrapper around the QT library it might be a version or system dependent flaw/ not really intended behavior. It would be interesting to try it again with the current version of QT.

(My specs: Windows 7 64bit, Python 2.7.2 64bit, PySide 1.2.1 wrapping Qt 4.8)

Upvotes: 1

TheDarkKnight
TheDarkKnight

Reputation: 27631

What you're seeing is the area of the Window beyond the QGraphicsView. You'll probably also find that you can resize the window and display more of the border.

To fix it, constrain the size of the window to the size of the QGraphicsView. As you've not set this in your example code, it would be the size of the pixmap.

So add these lines after declaring the window: -

window.setMaximumWidth(200);
window.setMaximumHeight(200);

Doing this will restrict the window from being resized greater than those values, so if you need to resize it beyond that, you'll need a larger QGraphicsView and QGraphicsScene.

Upvotes: 2

Related Questions