【问题标题】:Qt.ScrollBarAsNeeded not showing scrollbar when it's actually neededQt.ScrollBarAsNeeded 在实际需要时不显示滚动条
【发布时间】:2015-11-25 20:54:37
【问题描述】:

我正在使用 PyQt5 实现一个 python 应用程序,在使用 QScrollArea 时遇到了一些问题。这是我的应用程序的布局:

它由 2 个QScrollArea(左右窗格)和一个QMdiArea(中心小部件)组成,排列成一个QHBoxLayout。当我通过单击控件展开左窗格上的小部件时,QScrollAreaQWidget 的高度大于QScrollArea 本身的高度,滚动条出现(如预期的那样),但它是与QScrollArea 的内容重叠。为了解决这个问题,我重新实现了resizeEvent,为滚动条添加了必要的空间(此时一切正常。

现在,当我手动调整主窗口的大小时,左侧窗格获得更多空间,滚动条应该消失(但它没有)并且它与窗格的小部件重叠:

我还尝试手动切换滚动条的可见性(当收到 resizeEvent 时):当我这样做时,我可以成功隐藏滚动条但是我不能再次显示它(不管我是否调用 @987654337 @ 在滚动条上)。这会导致添加滚动条的空间,但缺少滚动条并且窗格的内容不可滚动:

下面是窗格小部件的实现:

class Pane(QScrollArea):

    MinWidth = 186

    def __init__(self, alignment=0, parent=None):
        super().__init__(parent)
        self.mainWidget = QWidget(self)
        self.mainLayout = QVBoxLayout(self.mainWidget)
        self.mainLayout.setAlignment(alignment)
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        self.mainLayout.setSpacing(0)
        self.setContentsMargins(0, 0, 0, 0)
        self.setFrameStyle(QFrame.NoFrame)
        self.setFixedWidth(Pane.MinWidth)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAsNeeded)
        self.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Ignored)
        self.setWidgetResizable(True)
        self.setWidget(self.mainWidget)

    def resizeEvent(self, resizeEvent):
        if self.viewport().height() < self.widget().height():
            self.setFixedWidth(Pane.MinWidth + 18)
            # THIS DOESN'T WORK
            #self.verticalScrollBar().show()
        else:
            self.setFixedWidth(Pane.MinWidth)
            #self.verticalScrollBar().hide()

    def addWidget(self, widget):
        self.mainLayout.addWidget(widget)

    def removeWidget(self, widget):
        self.mainLayout.removeWidget(widget)

    def update(self, *__args):
        for item in itemsInLayout(self.mainLayout):
            item.widget().update()
        super().update(*__args)

我想要实现的非常简单(但实际上似乎并不那么简单):我想仅在需要时在左/右窗格小部件上动态显示垂直滚动条,并为滚动条添加必要的空间所以它不会与QScrollArea 中的小部件重叠。

在有人问之前,我已经尝试过这样做:

def resizeEvent(self, resizeEvent):
    if self.viewport().height() < self.widget().height():
        self.setFixedWidth(Pane.MinWidth + 18) 
        scrollbar = self.verticalScrollbar()
        scrollbar.setVisible(True)
        self.setVerticalScrollBar(scrollbar) ## APP CRASH
    else:
        self.setFixedWidth(Pane.MinWidth)
        #self.verticalScrollBar().hide()

这会导致我的应用程序崩溃。 我希望有人已经遇到过这个问题并且能够帮助我。

编辑:我在 OSX Yosemite 10.10.4 下使用针对 Qt5.5 编译的 PyQt5.5,使用 clang。

【问题讨论】:

  • 首先尝试将您的滚动区域的 setWidgetResizable 设置为 true
  • 它已经设置为 True,所以我猜问题出在其他地方

标签: python qt python-3.x pyqt5 qscrollarea


【解决方案1】:

对我来说,一切似乎都按预期工作,无需任何变通方法。但是,我强烈怀疑您的真实代码中还有其他限制,您没有在您的问题中透露。

更新

下面是一个简单的例子,当滚动条显示/隐藏时调整滚动区域的大小:

import sys
from PyQt5 import QtCore, QtGui, QtWidgets

class Window(QtWidgets.QMainWindow):
    def __init__(self):
        super(Window, self).__init__()
        widget = QtWidgets.QWidget(self)
        layout = QtWidgets.QHBoxLayout(widget)
        self.mdi = QtWidgets.QMdiArea(self)
        self.leftScroll = Pane(
            QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft, self)
        self.rightScroll = Pane(
            QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft, self)
        layout.addWidget(self.leftScroll)
        layout.addWidget(self.mdi)
        layout.addWidget(self.rightScroll)
        self.setCentralWidget(widget)
        for scroll in self.leftScroll, self.rightScroll:
            for index in range(4):
                widget = QtWidgets.QTextEdit()
                widget.setText('one two three four five')
                scroll.addWidget(widget)

class Pane(QtWidgets.QScrollArea):
    MinWidth = 186

    def __init__(self, alignment=0, parent=None):
        super().__init__(parent)
        self.mainWidget = QtWidgets.QWidget(self)
        self.mainLayout = QtWidgets.QVBoxLayout(self.mainWidget)
        self.mainLayout.setAlignment(alignment)
        self.mainLayout.setContentsMargins(0, 0, 0, 0)
        self.mainLayout.setSpacing(0)
        self.setContentsMargins(0, 0, 0, 0)
        self.setFrameStyle(QtWidgets.QFrame.NoFrame)
        self.setFixedWidth(Pane.MinWidth)
        self.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.setVerticalScrollBarPolicy(QtCore.Qt.ScrollBarAsNeeded)
        self.setSizePolicy(QtWidgets.QSizePolicy.Maximum,
                           QtWidgets.QSizePolicy.Ignored)
        self.setWidgetResizable(True)
        self.setWidget(self.mainWidget)
        self.verticalScrollBar().installEventFilter(self)

    def addWidget(self, widget):
        self.mainLayout.addWidget(widget)

    def removeWidget(self, widget):
        self.mainLayout.removeWidget(widget)

    def eventFilter(self, source, event):
        if isinstance(source, QtWidgets.QScrollBar):
            if event.type() == QtCore.QEvent.Show:
                self.setFixedWidth(Pane.MinWidth + source.width())
            elif event.type() == QtCore.QEvent.Hide:
                self.setFixedWidth(Pane.MinWidth)
        return super(Pane, self).eventFilter(source, event)

if __name__ == '__main__':

    app = QtWidgets.QApplication(sys.argv)
    window = Window()
    window.setGeometry(500, 300, 800, 300)
    window.show()
    sys.exit(app.exec_())

【讨论】:

  • 我尝试了您的代码,但问题仍然存在:i.imgur.com/O2o0iil.png。您在哪个平台上尝试过代码?也许这是 OSX 唯一的问题。
  • @DanielePantaleone。是的,我怀疑还有其他因素。我在 Linux 上,无法在 OSX 上进行测试。您可能应该编辑您的问题,以明确您正在使用哪些特定版本的 OSX 和 Qt。如果您添加了在 OSX 上为您重现问题的最简单示例,这也会有很大帮助:即,可能只是一个包含一个小部件的 QScrollArea
  • 我修改了您的代码,为每个窗格添加了 1 个小部件(大于滚动区域),但问题仍然存在。过几天我会在Linux下试一试。
  • 在 Windows 8.1 和 Linux Ubuntu 14.04 上测试过,问题仍然存在。
  • @DanielePantaleone。测试了什么?我刚刚在 Windows 上尝试了我的脚本,它工作得很好。具体来说:当垂直调整窗口大小时,小部件会水平调整大小以适应滚动条,并相应地重新包装它们的文本。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-01-26
  • 2021-10-12
  • 1970-01-01
  • 2019-11-20
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多