QGraphicsView带滚动条时出现不需要的边距

5
我正在开发一个视频播放器,使用QGraphicsView来显示视频。 QGraphicsView 显示了一个只包含当前视频帧的 QGraphicsPixmapItemQGraphicsScene。视图的背景是黑色。
只要帧小于视图,则一切正常,视频帧将显示在视图中心,其余视图为黑色。当视图与帧大小相同时,仅显示帧,没有背景(显然)。当视频帧大于视图时,将显示滚动条,以便用户可以滚动查看帧的其他部分。
问题:当显示滚动条时,可能会卷过视频帧。底部和右侧有 8 个像素的边距显示了背景。如果视频帧大于视图,则不应该显示任何背景,并且不应该超出视频帧的范围滚动。
我简化了问题,在短代码中演示了这个问题,显示了一个带有绿色背景的200x200 px红色QPixmapQGraphicsView中。
#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();
}

我还提供了一个问题的图像(黑色边框不包含在示例代码中):http://imgur.com/4X5eyhC

左侧窗口中,QGraphicsView与矩形大小相同,在右侧窗口中,它略小,因此显示滚动条。并且背景也可见(不应该可见)。

我已经尝试设置QWidgetQGraphicsViewQGraphicsScene的sceneRect和各种其他属性,但没有发现可以解决这个问题的方法。

我还尝试在虚拟机中运行示例问题,以排除我的Qt/KDE版本存在缺陷的可能性。

我不知道为什么滚动条出现时背景会突然出现。我该如何摆脱它?如果无法实现,你有什么解决办法?

谢谢您提前帮忙。


你有没有研究过 QMediaPlayer?(我很好奇) - Son-Huy Pham
这是一项大学课程作业,需要使用Qt编写自己的原始YUV解码器和视频播放器,所以不能简单地使用QMediaPlayer / Phonon或其他解码器/视频播放组件/框架。 :-) - david
为什么不移除滚动条并确保视图位于0,0的中心位置呢? setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - Son-Huy Pham
视频显示框架大于显示屏时,必须具备滚动条,因此我无法移除滚动条。 - david
5个回答

6

问题是 QGraphicsView::fitInView() 存在一个他们并不关心的缺陷:https://bugreports.qt.io/browse/QTBUG-11945

不要重新实现自己的 fitInView,只需在创建视图时删除视图的边距即可。

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

在Qt 5中,view.setFrameStyle(QFrame.NoFrame)已经足够了。 - Hulud

2
你看到的是QGraphicsView之外的窗口区域。你可能还会发现,你可以调整窗口大小并显示更多的边框。
为了解决这个问题,将窗口的大小限制为QGraphicsView的大小。由于在你的示例代码中没有设置这个大小,所以它应该是pixmap的大小。
因此,在声明窗口后添加以下行:-
window.setMaximumWidth(200);
window.setMaximumHeight(200);

这样做将限制窗口的大小不能超过这些值,因此如果您需要调整大小超出这个范围,您需要一个更大的QGraphicsView和QGraphicsScene。


我知道当视图大于场景时,背景/边框将可见。问题是当滚动条可见时出现的背景/边距(即使场景大于视图!)。即使添加了两行代码以限制窗口大小,问题仍然存在。当向右/向下滚动时,仍会显示绿色背景。你测试过吗?如果你没有看到绿色背景,你使用的Qt版本是什么? - david
是的,我使用在OSX上运行的Qt 5测试了您的代码,并看到了您描述的效果。添加这两行代码对我有用。您现在还能调整窗口大小吗? - TheDarkKnight
我正在Linux/KDE上使用Qt 4.8.4。也许Qt 5有不同的行为或者这是我的版本中的一个错误。我可以调整窗口大小使其变小,但不能超过200x200。一旦我将窗口调整为199x199,背景就会再次可见。:-/ - david
1
如果您尝试了Qt 5,请告诉我们是否解决了您的问题。 - TheDarkKnight

1

我在使用 PySide 封装的 Qt 时尝试了问题中的代码片段,与 Python 几乎相同。

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_())

滚动条出现了,但我没有看到任何绿色区域!
我猜可能是因为它只是QT库的包装器,这可能是一个版本或系统相关的缺陷/不是真正预期的行为。尝试使用当前版本的QT再次尝试会很有趣。
(我的规格:Windows 7 64位,Python 2.7.2 64位,PySide 1.2.1包装Qt 4.8)

1

1
我创建了自己的fitInView()方法来解决问题。它基本上与原始的QGraphicView方法相同,除了边距:
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());
}

1
谢谢,这解决了我应用程序中讨论的问题。 - mvidelgauz
有趣的是,对我来说,这似乎只是减少了边距问题,但并没有完全解决它们... - mrg95

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接