Qt.ScrollBarAsNeeded 在实际需要时不显示滚动条
Qt.ScrollBarAsNeeded not showing scrollbar when it's actually needed
我正在使用 PyQt5 实现一个 python 应用程序,我在使用 QScrollArea 时遇到了一些问题。这是我的应用程序的布局:
它由 2 个 QScrollArea
(左右窗格)和一个 QMdiArea
(中心小部件)组成 QHBoxLayout
。当我通过单击控件展开左窗格中的小部件时,QScrollArea
的 QWidget
的高度大于 QScrollArea
本身的高度,滚动条出现(正如预期的那样),但它与 QScrollArea
的内容重叠。为了解决这个问题,我重新实现了resizeEvent
,为滚动条添加了必要的space(到此为止一切正常。
现在,当我手动调整 Main Window 大小时,左窗格变得更多 space 并且滚动条应该消失(但它没有)并且它与窗格的小部件重叠:
我还尝试手动切换滚动条的可见性(当收到 resizeEvent 时):当我这样做时,我可以成功地隐藏滚动条但是我不能再次显示它(不管我调用setVisible(True)
在滚动条上)。这导致添加了滚动条的 space,但滚动条丢失并且窗格的内容不可滚动:
下面是窗格小部件的实现:
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)
我想要实现的目标非常简单(但实际上它似乎并不那么简单):我想仅在需要时在我的 left/right 窗格小部件上动态显示垂直滚动条,并添加必要的space 用于滚动条,因此它不会与 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。
一切似乎都按我的预期工作,不需要任何变通办法。但是,我强烈怀疑您的真实代码中还有您没有在问题中透露的其他限制。
更新
下面是一个简单的示例,当滚动条为 shown/hidden:
时调整滚动区域的大小
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_())
我正在使用 PyQt5 实现一个 python 应用程序,我在使用 QScrollArea 时遇到了一些问题。这是我的应用程序的布局:
它由 2 个 QScrollArea
(左右窗格)和一个 QMdiArea
(中心小部件)组成 QHBoxLayout
。当我通过单击控件展开左窗格中的小部件时,QScrollArea
的 QWidget
的高度大于 QScrollArea
本身的高度,滚动条出现(正如预期的那样),但它与 QScrollArea
的内容重叠。为了解决这个问题,我重新实现了resizeEvent
,为滚动条添加了必要的space(到此为止一切正常。
现在,当我手动调整 Main Window 大小时,左窗格变得更多 space 并且滚动条应该消失(但它没有)并且它与窗格的小部件重叠:
我还尝试手动切换滚动条的可见性(当收到 resizeEvent 时):当我这样做时,我可以成功地隐藏滚动条但是我不能再次显示它(不管我调用setVisible(True)
在滚动条上)。这导致添加了滚动条的 space,但滚动条丢失并且窗格的内容不可滚动:
下面是窗格小部件的实现:
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)
我想要实现的目标非常简单(但实际上它似乎并不那么简单):我想仅在需要时在我的 left/right 窗格小部件上动态显示垂直滚动条,并添加必要的space 用于滚动条,因此它不会与 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。
一切似乎都按我的预期工作,不需要任何变通办法。但是,我强烈怀疑您的真实代码中还有您没有在问题中透露的其他限制。
更新
下面是一个简单的示例,当滚动条为 shown/hidden:
时调整滚动区域的大小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_())