强制QWidget占用QScrollArea中的所有可用高度

时间:2017-03-20 22:05:45

标签: python c++ qt pyqt qt5

我正在尝试用QHBoxLayout创建QScrollArea,里面包含一行od QWidgets。我希望小部件占据所有可用高度并相应地调整它的大小。

我的小工具是QLabel,里面显示缩放尺寸的QPixmaps。在我的项目中,这些是照片。我实现了heightForWidth和sizeHint方法来实现良好的缩放。我仍然无法达到正确的身高。

默认情况下,小部件会缩放,因此scrollarea不需要滚动条。

不需要滚动条

我使用了滚动小部件的sizePolicy,但只能强制小部件的大小等于sizeHint返回的最大大小。然后水平滚动处于活动状态。

小部件的最大尺寸超出窗口高度

当我更改sizeHint以返回QSize(width(),heightForWidth(width()))时,我发现width()最多返回640像素,而且不会更多。我无法弄清楚640这个限制的来源。

有没有办法在我的布局中删除640px的宽度限制,还是有办法强制小部件扩展到窗口高度?

class ImageWidget(QLabel):
    PIXMAP_SIZE = QSize(1000, 500)

    def __init__(self, parent=None):
        super(ImageWidget, self).__init__(parent)

        self._imagePixmap = QtGui.QPixmap(self.PIXMAP_SIZE)
        self._imagePixmap.fill(QtGui.QColor(Qt.green))

        self.setScaledContents(False)
        self.setSizePolicy(QSizePolicy.Maximum, QSizePolicy.Maximum)
        self.setStyleSheet("border:1px solid red;")

    def paintEvent(self, event):
        size = self.size()
        point = QPoint(0, 0)
        scaledPix = self._imagePixmap.scaled(size, Qt.KeepAspectRatio, Qt.SmoothTransformation)
        point.setX((size.width() - scaledPix.width())/2)
        point.setY((size.height() - scaledPix.height())/2)
        QtGui.QPainter(self).drawPixmap(point, scaledPix)

    def heightForWidth(self, width):
        return self._imagePixmap.height() * width / self._imagePixmap.width() if self._imagePixmap.width() else 0

    def hasHeightForWidth(self):
        return self._imagePixmap is not None

    def sizeHint(self):
        return QSize(self.width(), self.heightForWidth(self.width()))
        # self.width() has max value of 640 !
        #return self.PIXMAP_SIZE


class App(QMainWindow):
    def __init__(self):
        super(App, self).__init__()

        self.seriesLayout = QHBoxLayout()

        scrollWidget = QWidget()
        scrollWidget.setSizePolicy(QSizePolicy.MinimumExpanding, QSizePolicy.Maximum)
        scrollWidget.setLayout(self.seriesLayout)

        scroll = QScrollArea()
        scroll.setWidgetResizable(True)
        scroll.setWidget(scrollWidget)

        self.setCentralWidget(scroll)

        for col in range(5):
            self.seriesLayout.addWidget(ImageWidget())

1 个答案:

答案 0 :(得分:0)

我最终关注了评论并为我的scrollarea添加了自定义调整大小事件。 我使用viewport().height()作为首选高度并计算所需宽度,询问每个小部件有关首选widthForHeight()的信息。这当然只适用于我实现此方法的自定义小部件,但我确信可以扩展为sizeHint()

https://github.com/MrCappuccino/Tracey/blob/testing/src/TriangleMesh.cpp#L35-L48

无论如何,这是代码:

class MyScrollArea(QScrollArea):
    def __init__(self, parent=None):
        super(MyScrollArea, self).__init__(parent)
        self.setWidgetResizable(True)
        self.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOff)
        self.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)

        self.layout = QHBoxLayout()
        self.layout.setSpacing(30)

        scroll = QWidget()
        scroll.setLayout(self.layout)
        self.setWidget(scroll)

    def eventFilter(self, obj, event):
        if obj == self.widget() and event.type() == QEvent.Resize:
            self.widget().resize(self.calcViewportSize())
            return True

        return super(MyScrollArea, self).eventFilter(obj, event)

    def calcViewportSize(self):
        height = self.viewport().height()

        layoutMargins = self.layout.contentsMargins()
        heightForCalc = height - layoutMargins.top() - layoutMargins.bottom()

        width = self.calcWidthForHeight(heightForCalc)
        return QSize(width, height)

    def calcWidthForHeight(self, height):
        sum = 0
        for wgt in range(self.layout.count()):
            sum += self.layout.itemAt(wgt).widget().widthForHeight(height)

        if self.layout.count() > 1:
            sum += self.layout.spacing() * (self.layout.count()-1)
        return sum

class App(QMainWindow):
    def __init__(self):
        super(App, self).__init__()

        self.scroll = MyScrollArea()
        self.setCentralWidget(self.scroll)

        for col in range(3):
            self.scroll.layout.addWidget(ImageWidget())