带有滚动条的 QGraphicsView 内不需要的边距
Posted
技术标签:
【中文标题】带有滚动条的 QGraphicsView 内不需要的边距【英文标题】:Unwanted margin inside QGraphicsView with Scrollbars 【发布时间】:2013-06-20 20:52:25 【问题描述】:我正在开发一个视频播放器,使用QGraphicsView
来显示视频。 QGraphicsView
显示一个 QGraphicsScene
和一个包含当前视频帧的 QGraphicsPixmapItem
。视图的背景是黑色的。
只要帧小于视图,一切都好,视频帧显示在视图的中心,视图的其余部分是黑色的。当视图与框架大小相同时,仅显示框架,(显然)没有背景。当视频帧大于视图时,会显示滚动条,以便用户可以滚动查看帧的其他部分。
问题:当显示滚动条时,可以滚动超过视频帧。背景可见的底部和右侧有 8 个像素的边距。如果视频帧大于视图,则应该没有可见的背景,并且不能滚动超过视频帧。
我将问题简化为演示问题的简短源代码,在带有绿色背景的 QGraphicsView
中显示 200x200 像素的红色 QPixmap
。
#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
的大小与矩形相同,在右侧窗口中它稍微小一些,因此会显示滚动条。而且背景是可见的(它不应该是可见的)。
我已经尝试设置 sceneRect 和 QWidget
、QGraphicsView
和 QGraphicsScene
的各种其他属性,但没有发现任何改变问题的地方。
我还尝试在虚拟机中运行示例问题,以排除我的 Qt/KDE 版本存在错误的可能性。
我不知道为什么有滚动条时会突然显示背景。我怎样才能摆脱它?如果这不可能,您知道我该如何解决吗?
提前致谢。
【问题讨论】:
你看过QMediaPlayer吗? (我真的很好奇) 使用Qt编写自己的原始YUV解码器+视频播放器是大学的课程作业,所以我不能只使用QMediaPlayer/Phonon或其他一些解码器/视频播放组件/框架。 :-) 为什么不移除滚动条并确保您的视图以 0,0 为中心? setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 如果帧大于显示,视频显示需要有滚动条,所以我不能去掉滚动条。 【参考方案1】:问题是他们不关心的 QGraphicsView::fitInView() 的错误:https://bugreports.qt.io/browse/QTBUG-11945
与其重新实现您自己的 fitInView,不如在创建视图时从视图中删除边距。
view.setViewportMargins(-2, -2, -2, -2)
view.setFrameStyle(QFrame.NoFrame)
【讨论】:
【参考方案2】:您看到的是 QGraphicsView 之外的窗口区域。您可能还会发现您可以调整窗口大小并显示更多边框。
要修复它,请将窗口的大小限制为 QGraphicsView 的大小。由于您没有在示例代码中设置它,因此它将是像素图的大小。
所以在声明窗口后添加这些行:-
window.setMaximumWidth(200);
window.setMaximumHeight(200);
这样做会限制窗口被调整到大于这些值,所以如果你需要调整它的大小,你需要一个更大的 QGraphicsView 和 QGraphicsScene。
【讨论】:
我知道当视图大于场景时背景/边框将可见。问题是滚动条可见时出现的背景/边距(即使场景大于视图!)。添加两行以限制窗口大小后,问题仍然存在。向右/底部滚动时仍显示绿色背景。你测试过吗?如果您没有看到绿色背景,您使用的是哪个 Qt 版本? 是的,我用 Qt 5 测试了你的代码,在 OSX 上运行,看到了你描述的效果。添加这两条线为我修复了它。你还能调整窗口大小吗? 我在 Linux/KDE 上使用 Qt 4.8.4。也许 Qt 5 有不同的行为,或者是我的版本中的错误。我可以调整窗口大小以使其更小,不大于 200x200。一旦我将窗口大小调整为 199x199,背景就会再次可见。 :-/ 如果您尝试使用 Qt 5,请告诉我们是否为您解决了问题。【参考方案3】:我尝试了问题中的 sn-p,但在 Python 下使用 Qt 周围的 PySide 包装器。代码几乎相同。
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 位、包装 Qt 4.8 的 PySide 1.2.1)
【讨论】:
【参考方案4】:This is really just this question in disguise - 看看https://bugreports.qt.io/browse/QTBUG-42331并投票
简而言之,fitInView 具有硬编码的边距,这可能会造成各种破坏 - 最不重要的是现在您会丢失几个像素的显示区域,并且还可能会强制进行不必要的重新缩放。
ps。确保选择一个答案
【讨论】:
【参考方案5】:我修复了它,创建了我自己的 fitInView() 方法。和原来的QGraphicView方法基本一样,除了margin:
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());
【讨论】:
谢谢,这也解决了我的应用程序所讨论的问题以上是关于带有滚动条的 QGraphicsView 内不需要的边距的主要内容,如果未能解决你的问题,请参考以下文章