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_())
我正在尝试将小部件变成可滚动的小部件 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_())