QScrollArea,如何使我的中央小部件可滚动?

QScrollArea, how do I make my central widget scrollable?

我正在尝试将小部件变成可滚动的小部件 window。但是,我所做的只是打开一个完全独立于我的中央小部件的 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_()

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

简单解释:滚动区与主window没有关系,然后当主window是时不显示。

从不,曾经修改(或模仿)由pyuic

生成的文件

您对对象结构、Qt parent/ownership 以及滚动区域的设置方式有些困惑。

这也是由于您明显试图模仿由 pyuic 生成的文件的结构和行为,这应该 永远不会 完成。这些文件旨在按原样直接使用,无需任何修改,并在程序的主脚本中导入。
它们的特殊结构仅用于此目的,并且它们是 built 的方式不可模仿,因为通过代码创建 UI 只能通过子类化 QWidget 子类(QMainWindow , QDialog 等);试图模仿他们所做的事情不仅没有必要,而且大多数时候会导致混乱、错误和意外行为,就像您的情况一样。
打开(并且只是阅读)pyuic生成的文件的正当理由是为了了解小部件是如何创建的setupUi,请记住 setupUi 参数(通常,QMainWindows 为 MainWindow,QWidgets 为 Form,QDialogs 为 Dialog,除非顶级小部件在设计器的对象检查器中更改)是 ui 所在的主要小部件uilt。

只有在 真正 知道 she/he 在做什么的情况下,才应手动编辑这些文件。在极少数情况下,这被认为是必要的,通常是为了解决 uic 模块中非常具体的已知错误,这些错误通常在非常特定的条件和情况下出现。

发生了什么事?

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

小部件可以通过多种方式重新设置父级:通过使用 setWidget() 为滚动区域设置小部件,或者通过将小部件设置为 中央小部件 到QMainWindow.

您的代码发生的情况是,您创建了一个新的 QWidget,它成为 QMainWindow 的 child,具有以下行:

self.centralwidget = QtWidgets.QWidget(MainWindow)

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

self.scrollArea = QtWidgets.QScrollArea()

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

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

self.scrollArea.setWidget(self.centralwidget)

最后,您要将该小部件设置为中央小部件,这会将其重新设置为 再次 到主 window,结果是滚动区域将不再有小部件(QWidget 继承的 QObject 只能有一个父对象)。

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_())