Unwanted margin inside QGraphicsView with Scrollbars
Asked Answered
B

5

5

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.

Berth answered 20/6, 2013 at 20:52 Comment(4)
Have you looked into QMediaPlayer? (I'm honestly curious)Manilla
It's a course work for the university to write an own raw YUV decoder + video player with Qt, so I can't just use QMediaPlayer/Phonon or some other decoder/video playback components/frameworks. :-)Berth
Why not remove scroll bars and ensure you have your view centered on the 0,0? setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);Manilla
It's a requirement that the video display has scrollbars if the frame is greater than the display, so I can't remove the scrollbars.Berth
C
6

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)
Colchicine answered 22/1, 2020 at 19:38 Comment(0)
H
2

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.

Hexahydrate answered 21/6, 2013 at 8:38 Comment(4)
I know that the background/border will be visible when the view is greater than the scene. The problem is the background/margin that appears as soon as scroll bars are visible (even when the scene is greater than the view!). The problem persists after adding your two lines to restrict the window size. The green background is still shown when scrolling to the right/bottom. Have you tested that? If you don't see the green background, what Qt version are you using?Berth
Yes, I tested your code with Qt 5,running on OSX and saw the effect you described. Adding those 2 lines fixed it for me. Can you still resize the window?Hexahydrate
I'm using Qt 4.8.4 on Linux/KDE. Maybe Qt 5 has a different behaviour or it's a bug in my version. I can resize the window to make it smaller, not greater than 200x200. As soon as I resize the window to 199x199, the background is visible again. :-/Berth
If you try Qt 5, let us know if that fixed it for you.Hexahydrate
P
1

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)

Parrie answered 4/4, 2014 at 10:27 Comment(0)
P
1

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

Phone answered 5/5, 2015 at 11:23 Comment(0)
L
1

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());
}
Laquanda answered 26/2, 2017 at 21:32 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.