首页 > 解决方案 > QScrollArea,如何使我的中央小部件可滚动?

问题描述

我正在尝试将小部件变成可滚动窗口。然而,我所做的只是打开一个完全独立于我的中央小部件的 QScrollarea。

class Ui_MainWindow(object):

    def mainscreen(self, MainWindow):
        self.centralwidget = QtWidgets.QWidget(MainWindow)
        self.scrollArea = QtWidgets.QScrollArea()
        self.scrollArea.setWidget(self.centralwidget)
        

        MainWindow.setCentralWidget(self.centralwidget)



if __name__ == "__main__":
    import sys

    app = QtWidgets.QApplication(sys.argv)

    MainWindow = QtWidgets.QMainWindow()
    ui = Ui_MainWindow()
    ui.mainscreen(MainWindow)
    MainWindow.show()
    app.exec_()

这只是自行打开我的 MainWindow,打开滚动区域的唯一方法是执行 self.scrollarea.show 。我不知道 QScrollArea 是如何工作的,我应该怎么做?

标签: pythonpyqtpyqt5

解决方案


简单解释:滚动区域与主窗口无关,然后在主窗口时不显示。

永远不要修改(或模仿)由pyuic

您对对象结构、Qt 父/所有权以及如何设置滚动区域感到困惑。

这也是由于您显然是在尝试模仿 pyuic 生成的文件的结构和行为,而这绝不应该这样做。这些文件旨在按原样直接使用,无需任何修改,并在程序的主脚本中导入。
它们的特殊结构仅用于此目的,并且它们的构建方式不能被模拟,因为通过代码创建 UI 只能通过继承 QWidget 子类(QMainWindow、QDialog 等)来完成;试图模仿他们所做的不仅是不必要的,而且大多数时候会导致混乱、错误和意外行为,就像你的情况一样。
打开的唯一正当理由(只需阅读)由 pyuic 生成的一个文件是用来setupUi学习如何在) 是构建 ui 的主要小部件。setupUiMainWindowFormDialog

只有当一个人真的知道她/他在做什么时,才应该手动编辑这些文件。很少有非常罕见的情况需要这样做,通常是为了解决 uic 模块中非常具体的已知错误,这些错误通常会在非常特定的条件和情况下出现。

怎么了?

然后,当使用现有小部件作为参数创建 QWidget 实例时,结果是新小部件成为现有小部件的级。

然后可以通过各种方式重新设置小部件:通过使用 为滚动区域setWidget()设置小部件,或者通过将小部件设置为QMainWindow的中央小部件。

您的代码发生的情况是您创建了一个新的 QWidget,它成为 QMainWindow 的级,其中包含以下行:

self.centralwidget = QtWidgets.QWidget(MainWindow)

然后创建一个滚动区域(没有任何父级):

self.scrollArea = QtWidgets.QScrollArea()

未使用父级创建的小部件通常被视为顶级窗口,除非它们被添加到布局中(或使用手动重新设置父级setParent(),但这是另一回事),这会导致父级(设置布局的小部件)采用新子小部件的所有权。否则,如果您尝试显示“无父”小部件,它将显示为顶级小部件,这意味着它将有自己的窗口,并且作为任何顶级小部件,它们只能通过手动调用show()setVisible(True)(这就是你的情况)。

然后您尝试设置centralwidget滚动区域的,这将导致重新设置它:

self.scrollArea.setWidget(self.centralwidget)

最后,您将该小部件设置为中央小部件,它将再次将其重新设置回主窗口,结果滚动区域将不再有小部件(QWidget 继承自的 QObjects 只能有一个父母)。

MainWindow.setCentralWidget(self.centralwidget)

正确的做法

解决方案是正确创建一个 QWidget (或 QMainWindow 在你的情况下)子类,将滚动区域设置为中央小部件(如果你想要它)并为其内容创建一个新的小部件:

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        self.scrollArea = QtWidgets.QScrollArea()
        self.setCentralWidget(self.scrollArea)
        self.scrollArea.setWidgetResizable(True)

        self.contents = QtWidgets.QWidget()
        self.scrollArea.setWidget(self.contents)

        # create a layout for the scroll area contents; using the target widget
        # as argument of the layout constructor automatically sets the layout on
        # the specified widget
        layout = QtWidgets.QVBoxLayout(self.contents)

        # the same as:
        # layout = QtWidgets.QVBoxLayout()
        # self.contents.setLayout(layout)

        for row in range(20):
            button = QtWidgets.QPushButton('button {}'.format(row + 1))
            layout.addWidget(button)


if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    mainWindow = MainWindow()
    mainWindow.show()
    sys.exit(app.exec_())

推荐阅读