QStackedWidget 开启倍数windows

QStackedWidget opening multiple windows

我已经使用 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).__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,结果是所有页面实际上都显示为顶级 windows。

当一个小部件被添加到布局中时,它就获得了它的所有权;如果布局已经设置为小部件,则添加到布局的小部件将重新设置为另一个小部件。如果您将布局设置为 afterwards.

,也会发生同样的情况

为什么第一页显示为单独的 window?为什么不显示第二个?
当一个新的 widget 在没有 parent 的情况下被创建时,它成为一个顶级 window;当一个小部件被添加到 new 堆叠布局时,Qt 会自动尝试显示它;您没有将布局设置为任何内容(如前所述,这将重新设置它的父级),结果是第一页显示为独立的 window.

现在,由于第一个“屏幕”只会在第一次显示,您可以将该小部件设置为中央小部件,然后将 Xyz 实例(实际上是 QStackedWidget 的子类)设置为 中央小部件。

请注意,如果 QWidget 是唯一显示的父窗口小部件,则无需使用 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_())