Python QStackedWidget打开多个窗口
我使用PyQt构建了一个小应用程序,据我所知,QStackedWidget用于制作多页应用程序。问题是它正在打开多个页面,而且我无法使用Python QStackedWidget打开多个窗口,python,pyqt,Python,Pyqt,我使用PyQt构建了一个小应用程序,据我所知,QStackedWidget用于制作多页应用程序。问题是它正在打开多个页面,而且我无法使用class Abc中的按钮重定向到class Xyz main.py from PyQt4 import QtGui, QtCore import sys class Window(QtGui.QMainWindow): def __init__(self, parent=None): super(Window, self).__ini
class Abc
中的按钮重定向到class Xyz
main.py
from PyQt4 import QtGui, QtCore
import sys
class Window(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.stacked_widget = QtGui.QStackedWidget()
layout = QtGui.QVBoxLayout()
layout.setContentsMargins(0,0,0,0)
layout.addWidget(self.stacked_widget)
widget = QtGui.QWidget()
widget.setLayout(layout)
self.setCentralWidget(widget)
widget_1 = Abc(self.stacked_widget)
widget_2 = Xyz(self.stacked_widget)
self.stacked_widget.addWidget(widget_1)
self.stacked_widget.addWidget(widget_2)
self.showMaximized()
class Abc(QtGui.QWidget):
def __init__(self, stacked_widget, parent=None):
super(Abc, self).__init__(parent)
self.stacked_widget = stacked_widget
self.frame = QtGui.QFrame()
self.frame_layout = QtGui.QVBoxLayout()
self.button = QtGui.QPushButton('Click me!')
self.button.clicked.connect(self.click)
self.frame_layout.addWidget(self.button)
self.frame.setLayout(self.frame_layout)
self.layout = QtGui.QVBoxLayout()
self.layout.addWidget(self.frame)
self.setLayout(self.layout)
self.showMaximized()
def click(self):
print("You clicked me!")
self.stacked_widget.setCurrentIndex(1)
class Xyz(QtGui.QWidget):
def __init__(self, parent=None):
super(Xyz, self).__init__(parent)
self.frame_layout = QtGui.QStackedLayout()
self.page1 = Page("Page 1", self.frame_layout)
self.page2 = Page("Page 2", self.frame_layout)
self.frame_layout.addWidget(self.page1)
self.frame_layout.addWidget(self.page2)
class Page(QtGui.QWidget):
def __init__(self, text, frame_layout, parent=None):
super(Page, self).__init__(parent)
print(self.width(), self.height())
self.frame_layout = frame_layout
self.frame = QtGui.QFrame()
self.frame_layout = QtGui.QVBoxLayout()
self.frame.setStyleSheet("background-color: rgb(191, 191, 191)")
self.label = QtGui.QLabel()
self.label.setText(text)
self.frame_layout.addWidget(self.label, alignment=QtCore.Qt.AlignCenter)
self.frame.setLayout(self.frame_layout)
self.layout = QtGui.QVBoxLayout()
self.layout.addWidget(self.frame)
self.layout.setContentsMargins(0,0,0,0)
self.setLayout(self.layout)
self.showMaximized()
print(self.width(), self.height())
if __name__ == "__main__":
app = QtGui.QApplication([])
window = Window()
window.show()
sys.exit(app.exec_())
主要问题是没有为
Xyz
小部件设置QStackedLayout,结果是所有页面实际上都将显示为顶级窗口
当一个小部件被添加到一个布局中时,它拥有它的所有权;如果布局已设置为小部件,则添加到布局的小部件将重新租给另一个小部件。如果随后设置布局,也会发生同样的情况
为什么它将第一页显示为一个单独的窗口?为什么不显示第二个呢?当在没有父窗口的情况下创建新窗口小部件时,它将成为顶级窗口;当一个小部件被添加到一个新的堆叠布局中时,Qt会自动尝试显示它;您没有将布局设置为任何设置(这将按照前面的解释重新分配),结果是第一个页面显示为独立窗口 现在,由于第一个“屏幕”将仅第一次显示,您可以将该小部件设置为中心小部件,然后将Xyz实例(实际上是一个QStackedWidget子类)设置为新的中心小部件 请注意,如果QFrame是显示的唯一父窗口小部件,则不需要使用QWidget来添加QFrame:您可以将QFrame子类化 这是一个更简单、更清晰的代码版本:
from PyQt4 import QtGui, QtCore
class Window(QtGui.QMainWindow):
def __init__(self, parent=None):
super(Window, self).__init__(parent)
self.startPage = Abc()
self.setCentralWidget(self.startPage)
self.startPage.startRequest.connect(self.buildPages)
def buildPages(self):
self.pages = Xyz()
self.setCentralWidget(self.pages)
class Abc(QtGui.QFrame):
startRequest = QtCore.pyqtSignal()
def __init__(self, parent=None):
super(Abc, self).__init__(parent)
layout = QtGui.QVBoxLayout(self)
self.button = QtGui.QPushButton('Click me!')
self.button.clicked.connect(self.startRequest)
layout.addWidget(self.button)
class Xyz(QtGui.QStackedWidget):
def __init__(self, parent=None):
super(Xyz, self).__init__(parent)
self.page1 = Page("Page 1")
self.page2 = Page("Page 2")
self.addWidget(self.page1)
self.addWidget(self.page2)
self.page1.switchRequest.connect(lambda: self.setCurrentIndex(1))
self.page2.switchRequest.connect(lambda: self.setCurrentIndex(0))
class Page(QtGui.QFrame):
switchRequest = QtCore.pyqtSignal()
def __init__(self, text, parent=None):
super(Page, self).__init__(parent)
layout = QtGui.QVBoxLayout(self)
# set the background only for QFrame subclasses (which also includes
# QLabel), this prevents setting the background for other classes,
# such as the push button
self.setStyleSheet('''
QFrame {
background-color: rgb(191, 191, 191)
}
''')
# when adding a widget to a layout, the layout tries to automatically
# make it as big as possible (based on the widget's sizeHint); so you
# should not use the alignment argument for layout.addWidget(), but for
# the label instead
self.label = QtGui.QLabel(text, alignment=QtCore.Qt.AlignCenter)
layout.addWidget(self.label)
self.switchButton = QtGui.QPushButton('Switch')
layout.addWidget(self.switchButton)
self.switchButton.clicked.connect(self.switchRequest)
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
你的问题有点模糊,就像你的代码一样。例如,
Xyz
小部件不包含任何内容,它的page1
和page2
小部件只是添加到没有设置为任何小部件的堆叠布局中(这就是为什么您将第一个页面视为单独的窗口,我将最终解释为什么第二个页面没有)。然后使用frame\u layout
参数创建页面
实例,将其设置为实例属性,然后将其覆盖。你能澄清一下小部件的结构是什么吗?@musicamante,我想要的是类Abc
中定义的一个按钮,单击该按钮,我将被重定向到Xyz
类,该类现在包含多个页面(在本例中为“第1页”和“第2页”)。然后,我想要一个在这些页面之间导航的功能。是否需要Xyz?据我所见,它似乎在任何方面都没有“专门化”,因此您的结构看起来有点过于复杂:您不能只使用一个QStackedWidget,直接将这两个页面添加到其中,然后添加函数在它们之间切换(索引1和索引2),忽略第一个页面。@musicamante,是的,有Xyz是绝对必要的。实际上,我的actaul项目包含50多页,我已经按照你的建议创建了这个项目,但是当我启动应用程序时,它会产生一种恼人的效果。看起来这些页面好像是一页一页地加载。这就是为什么我创建了一个带有QStackedLayout
的类Xyz来避免这种情况。您面临的问题之一并不取决于是否有Xyz
,而是因为您没有为该小部件设置布局(实际上它什么都不做),所以所有页面实际上都显示为独立的顶级窗口。开始页(带按钮的那一页)会在任何时候再次显示,还是只在开始时显示?这正是我所需要的。但仍然无法理解整个所有权概念。看起来PyQt不像我想象的那么简单。但是非常感谢,你已经解决了我的问题。@thedarklord我建议你仔细研究文档(我知道,它很长,要求很高,但相信我,它是值得的)。基本概念是QObject
子类(包括所有QWidget子类)只能有一个父类(或者根本没有父类!);当您在文档中读到类似“x拥有y”的内容时,通常意味着x
成为y
的所有者。简单地说,当您将widgetY添加到在widgetX上设置的布局中时,widgetX将成为widgetY的父级。但这对于QWidgets来说有点复杂。我知道文档对此有点模糊(尤其是整个“布局拥有所有权”)。默认情况下,没有QWIDGET父级的QWIDGET总是显示为顶层窗口小部件(如果将小部件添加到尚未设置到另一个小部件的布局),也会发生这种情况。如果您想添加一个小部件作为另一个C++的子窗口,您可以用它的父窗口小部件参数初始化它,手动使用,或者将它添加到一个布局中,这样的布局早晚都设置为父级,否则它将是一个顶层窗口。而DOC是面向C++的,它也适用于python:PyQt 99%的参数和返回值都是相同的(请记住,void
表示函数返回None
)。虽然有,但并不总是全面或完整的;顺便说一句,您可以将其用作仅在PyQt上可用的专用函数的参考。@thedarklord您是什么意思?给什么尺寸?