我如何着手在 PyQt5 中创建动态网格 QScrollarea?

How do I go about creating a dynamic grid QScrollarea in PyQt5?

我正在开发一些涉及创建作品space并在其中工作的自定义软件。我想在动态滚动区域网格中显示所有现有的工作空间目录,该网格由按钮组成,这些按钮根据滚动区域占用的屏幕空间量更改按钮的位置,以便尽可能多地插入尽可能多的按钮行。(所以基本上就像文件资源管理器一样,根据您调整 window 大小的方式更改文件夹和文件的布局以适应网格中的屏幕)我尝试使用滚动区域内的网格布局来执行此操作。我还尝试在 qvboxlayout 中添加 qhboxlayouts 无济于事,因为我不知道如何检查是否有 space 用于另一个按钮以从较低的 qhboxlayout 中删除一个按钮并附加到较高的按钮。

这是我当前的代码:



from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import QFileDialog

class Ui_AutoCal(object):
    def setupUi(self, AutoCal):
        AutoCal.setObjectName("AutoCal")
        AutoCal.resize(513, 551)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Preferred)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(AutoCal.sizePolicy().hasHeightForWidth())
        AutoCal.setSizePolicy(sizePolicy)
        AutoCal.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))
        AutoCal.setStyleSheet("*{\n"
"background-color: rgb(54, 54, 54);\n"
"color:rgb(255,255,255)\n"
"}\n"
"\n"
"QPushButton\n"
"{\n"
"border-radius: 25px;\n"
"}\n"
"\n"
"QLineEdit\n"
"{\n"
"color:rgb(0,0,0)\n"
"}")
        self.centralwidget = QtWidgets.QWidget(AutoCal)
        self.centralwidget.setObjectName("centralwidget")

        self.verticalLayout = QtWidgets.QVBoxLayout(self.centralwidget)
        self.verticalLayout.setObjectName("verticalLayout")
        self.groupBox = QtWidgets.QGroupBox(self.centralwidget)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.groupBox.sizePolicy().hasHeightForWidth())
        self.groupBox.setSizePolicy(sizePolicy)
        self.groupBox.setAlignment(QtCore.Qt.AlignCenter)
        self.groupBox.setObjectName("groupBox")
        self.verticalLayout_6 = QtWidgets.QVBoxLayout(self.groupBox)
        self.verticalLayout_6.setObjectName("verticalLayout_6")
        self.horizontalLayout_3 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_3.setObjectName("horizontalLayout_3")
        self.label = QtWidgets.QLabel(self.groupBox)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.label.sizePolicy().hasHeightForWidth())
        self.label.setSizePolicy(sizePolicy)
        self.label.setObjectName("label")
        self.horizontalLayout_3.addWidget(self.label)
        self.lineEdit = QtWidgets.QLineEdit(self.groupBox)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Preferred, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.lineEdit.sizePolicy().hasHeightForWidth())
        self.lineEdit.setSizePolicy(sizePolicy)
        self.lineEdit.setObjectName("lineEdit")
        self.horizontalLayout_3.addWidget(self.lineEdit)
        self.pushButton = QtWidgets.QPushButton(self.groupBox)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Fixed, QtWidgets.QSizePolicy.Fixed)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.pushButton.sizePolicy().hasHeightForWidth())
        self.pushButton.setSizePolicy(sizePolicy)
        self.pushButton.setObjectName("pushButton")

        # self.pushButton.clicked.connect(self.openFileNameDialog )

        self.horizontalLayout_3.addWidget(self.pushButton)
        self.verticalLayout_6.addLayout(self.horizontalLayout_3)
        self.horizontalLayout_4 = QtWidgets.QHBoxLayout()
        self.horizontalLayout_4.setObjectName("horizontalLayout_4")
        self.label_2 = QtWidgets.QLabel(self.groupBox)
        self.label_2.setObjectName("label_2")
        self.horizontalLayout_4.addWidget(self.label_2)
        self.lineEdit_2 = QtWidgets.QLineEdit(self.groupBox)
        self.lineEdit_2.setText("")
        self.lineEdit_2.setObjectName("lineEdit_2")
        self.horizontalLayout_4.addWidget(self.lineEdit_2)
        self.pushButton_2 = QtWidgets.QPushButton(self.groupBox)
        self.pushButton_2.setObjectName("pushButton_2")
        
        self.horizontalLayout_4.addWidget(self.pushButton_2)
        self.verticalLayout_6.addLayout(self.horizontalLayout_4)
        self.verticalLayout.addWidget(self.groupBox)
        self.verticalLayout_3 = QtWidgets.QVBoxLayout()
        self.verticalLayout_3.setObjectName("verticalLayout_3")
        self.groupBox_2 = QtWidgets.QGroupBox(self.centralwidget)
        self.groupBox_2.setEnabled(True)
        self.groupBox_2.setAlignment(QtCore.Qt.AlignCenter)
        self.groupBox_2.setObjectName("groupBox_2")
        self.verticalLayout_5 = QtWidgets.QVBoxLayout(self.groupBox_2)
        self.verticalLayout_5.setObjectName("verticalLayout_5")
        self.scrollArea = QtWidgets.QScrollArea(self.groupBox_2)
        sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Ignored, QtWidgets.QSizePolicy.Ignored)
        sizePolicy.setHorizontalStretch(0)
        sizePolicy.setVerticalStretch(0)
        sizePolicy.setHeightForWidth(self.scrollArea.sizePolicy().hasHeightForWidth())
        self.scrollArea.setSizePolicy(sizePolicy)
        self.scrollArea.setWidgetResizable(True)
        self.scrollArea.setObjectName("scrollArea")
        self.scrollAreaWidgetContents = QtWidgets.QWidget()
        self.gridLayout = QtWidgets.QGridLayout(self.scrollAreaWidgetContents)
        # self.scrollAreaWidgetContents.setGeometry(QtCore.QRect(0, 0, 467, 331))
        self.scrollAreaWidgetContents.setObjectName("scrollAreaWidgetContents")
        self.scrollArea.setWidget(self.scrollAreaWidgetContents)
        self.scrollArea.setHorizontalScrollBarPolicy(QtCore.Qt.ScrollBarAlwaysOff)
        self.fillScrollArea()

        self.verticalLayout_5.addWidget(self.scrollArea)
        self.verticalLayout_3.addWidget(self.groupBox_2)
        self.verticalLayout.addLayout(self.verticalLayout_3)
        AutoCal.setCentralWidget(self.centralwidget)
        self.menubar = QtWidgets.QMenuBar(AutoCal)
        self.menubar.setGeometry(QtCore.QRect(0, 0, 513, 22))
        self.menubar.setObjectName("menubar")
        self.menuWorkSpace = QtWidgets.QMenu(self.menubar)
        self.menuWorkSpace.setObjectName("menuWorkSpace")
        self.menuRecipients = QtWidgets.QMenu(self.menubar)
        self.menuRecipients.setObjectName("menuRecipients")
        AutoCal.setMenuBar(self.menubar)
        self.statusbar = QtWidgets.QStatusBar(AutoCal)
        self.statusbar.setObjectName("statusbar")
        AutoCal.setStatusBar(self.statusbar)
        self.menubar.addAction(self.menuWorkSpace.menuAction())
        self.menubar.addAction(self.menuRecipients.menuAction())

        self.retranslateUi(AutoCal)
        QtCore.QMetaObject.connectSlotsByName(AutoCal)

    def retranslateUi(self, AutoCal):
        _translate = QtCore.QCoreApplication.translate
        AutoCal.setWindowTitle(_translate("AutoCal", "AutoCal"))
        self.groupBox.setTitle(_translate("AutoCal", "Create New WorkSpace"))
        self.label.setText(_translate("AutoCal", "Choose WorkSpace Directory"))
        self.pushButton.setText(_translate("AutoCal", "Browse"))
        self.label_2.setText(_translate("AutoCal", "WorkSpace Name"))
        self.pushButton_2.setText(_translate("AutoCal", "Create"))
        self.groupBox_2.setTitle(_translate("AutoCal", "Choose Existing WorkSpace"))
        self.menuWorkSpace.setTitle(_translate("AutoCal", "WorkSpace"))
        self.menuRecipients.setTitle(_translate("AutoCal", "Recipients"))

    def fillScrollArea(self):

        for i in range(50):
            for j in range(50):
                self.gridLayout.addWidget(QtWidgets.QPushButton("Test"), i, j)



if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    AutoCal = QtWidgets.QMainWindow()
    ui = Ui_AutoCal()
    ui.setupUi(AutoCal)
    AutoCal.show()
    sys.exit(app.exec_())

这会产生以下滚动区域(忽略表格):

当前滚动区域

主要问题是我需要按钮始终位于 scrollArea 的可见部分,而如您所见,其中许多按钮隐藏在 scrollarea 后面,并且它们的文本被截断。我知道这是因为我的函数应用于网格布局的定位,但我不知道任何其他定位它们的方法。我还需要按钮是动态的,因为如果水平 space 在较高行中变得更大,则较低行中的按钮将占用 space。因此我也不需要水平滚动,这就是它被禁用的原因。

我的问题现已解决。虽然流布局很有用,但简单地使用 QListWidget 更直观。非常感谢 eyllanesc 和 musicamante 的帮助。

对于遇到相同问题的任何人,只需创建一个 QlistWidget 并向其添加项目即可获得所需的结果:

size = QSize(100,100)
self.listWidget = QListWidget()
size = QtCore.QSize(80,80)
self.listWidget.setResizeMode(QListView.Adjust)
self.listWidget.setIconSize(size)
self.listWidget.itemDoubleClicked.connect(self.itemClicked)
self.listWidget.setViewMode(QListView.IconMode)