具有固定尺寸的滚动区域

Scrollarea with fixed dimensions

我对标题感到抱歉,但我无法以更好的方式解释这个主题。

我有一个带有网格布局的滚动区域,它的行数和列数可变。在网格的每个单元格中,我都有一个 QLabel。 我希望 scrollarea 的视口有一个固定的大小,这样我就可以在不使用滚动条的情况下只查看一定数量的标签。 相反,在这段代码中,我查看了所有标签,如果它们的数量发生变化,它们总是插入到视口的 space 中,并且它们的尺寸发生了变化。

我应该在不更改行 self.scrollArea.setWidgetResizable(False) 的情况下执行此操作,因为如果设置为 True,我正在实施的缩放系统将无法工作。

可能吗?

import sys


from PyQt5.QtCore import Qt, QRect
from PyQt5.QtWidgets import ( QVBoxLayout, QHBoxLayout, QGridLayout, QApplication, QMainWindow,
                             QLabel, QWidget, QPushButton, QScrollArea
                             )



class MyScrollingArea(QWidget):

    def __init__(self, parent=None):
        super(MyScrollingArea).__init__()
        self.vertLayout = QVBoxLayout()
        self.vertLayout.setContentsMargins(0, 0, 0, 0)
        self.vertLayout.setSpacing(0)
        self.gridLayout = QGridLayout()
        self.gridContainer = QWidget()
        self.scrollArea = QScrollArea()
        self.scrollArea.setVerticalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.scrollArea.setHorizontalScrollBarPolicy(Qt.ScrollBarAlwaysOn)
        self.scrollArea.setWidgetResizable(False)
        self.scrollArea.setWidget(self.gridContainer)
        self.populate( )
        buttonsArea=self.zoomMenu()
        self.gridContainer.setLayout(self.gridLayout )
        self.vertLayout.addWidget(self.scrollArea)
        self.vertLayout.addWidget(buttonsArea)
        self.setLayout(self.vertLayout )

    def zoomMenu(self):
           widButtonFooter = QWidget()
           layButtonFooter = QHBoxLayout()
           widButtonFooter.setLayout(layButtonFooter)
           butZommMinus = QPushButton("-")
           butZommPlus = QPushButton("+")
           layButtonFooter.addWidget(butZommMinus)
           layButtonFooter.addWidget(butZommPlus) 
           return widButtonFooter

    def populate(self):
        colors = (  "navy","green", "magenta","cyan", "yellow","red", "orange", "blue","purple", "gold","silver", "lightblue", "lime" )
        for row in range(0,10):
            for col in range (0,20):
                self.addLabel(row,col,colors[row])

    def addLabel(self,row,col,color):
        label = MyLabel(row,col,80,100,color,str(row) + "." + str(col))
        self.gridLayout.addWidget(label,row,col) 

    def resizeEvent(self, event):
        self.gridContainer.resize(self.width(), self.height())
        super(MyScrollingArea, self).resizeEvent(event)



class MyLabel(QLabel):
    def __init__(self,row,col, w, h, color, text):
        super().__init__()
        self.color=color
        self.setStyleSheet("border:10px solid " + self.color + ";")
        self.setText(text)
        self.setAlignment(Qt.AlignCenter)
        self.setGeometry(QRect(0, 0, w, h))

    def mousePressEvent(self,QMouseEvent):
        if QMouseEvent.button() == Qt.LeftButton:
            self.setStyleSheet("background-color:" + self.color + ";")
        elif QMouseEvent.button() == Qt.RightButton:
            self.setStyleSheet("border:10px solid " + self.color + ";")

class MyGrid(QMainWindow):

    def __init__(self):
        super().__init__()
        self.resize(1000, 800)
        self.saScrollMeasureBox = MyScrollingArea()
        widPanelMeasure = QWidget()
        layvPanelMeasure = QVBoxLayout()
        widPanelMeasure.setLayout(layvPanelMeasure)
        layvPanelMeasure.addWidget(self.saScrollMeasureBox)
        self.setCentralWidget(widPanelMeasure)
        
        
if __name__ == '__main__':
    app = QApplication(sys.argv)
    window = MyGrid()

    window.show()
    app.exec_()

布局管理器没有特定的尺寸,只有尺寸提示和可能的最小 and/or 最大尺寸,所有这些都基于它包含的项目,使用它们的尺寸提示、约束和策略。

在要添加到布局的小部件上设置几何形状毫无意义,因为布局管理它们的大小和位置。解决方案是改用setFixedSize

由于布局还会自动调整小部件的位置,如果有 space 剩余(其中 none 能够扩展其大小),您可以在末尾添加一个拉伸布局,以确保它们始终以相同的方式 spaced,即使边缘上有更多 space 可用。对于盒装布局,使用 addStretch() 就足够了,但对于网格布局,您必须指定特定行和列的拉伸。

为了更好地理解 Qt 如何处理所有这些(广泛的和复杂的)方面,我建议您阅读更多关于 hints and policies, QSizePolicy and layout management, and do some more experiments with more simple cases, even using Designer

以下修改要求widgetResizable 属性设置为True.

class MyScrollingArea(QWidget):
    # ...
    def populate(self):
        colors = (
            "navy", "green", "magenta", "cyan", "yellow", "red", "orange", 
            "blue", "purple", "gold", "silver", "lightblue", "lime"
        )
        rows = 10
        columns = 20
        for row in range(rows):
            for col in range (columns):
                self.addLabel(row, col, colors[row])
        self.gridLayout.setColumnStretch(columns, 1)
        self.gridLayout.setRowStretch(rows, 1)


class MyLabel(QLabel):
    def __init__(self, row, col, w, h, color, text):
        super().__init__()
        self.color = color
        self.setStyleSheet("border:10px solid " + self.color + ";")
        self.setText(text)
        self.setAlignment(Qt.AlignCenter)
        self.setFixedSize(w, h)

我建议您更加小心地使用 spaces,在逗号后面(和等号周围)应该始终使用它以提高可读性。阅读官方Style Guide for Python Code.