QStackedWidget открывает несколько windows - PullRequest
1 голос
/ 01 августа 2020

Я создал небольшое приложение с использованием PyQt, и, насколько мне известно, QStackedWidget используется для создания многостраничных приложений. Проблема в том, что он открывает несколько страниц, а также я не могу перенаправить на class Xyz с помощью кнопки в class Abc.

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

1 Ответ

2 голосов
/ 02 августа 2020

Основная проблема заключается в том, что вы не устанавливаете QStackedLayout для виджета Xyz, в результате все страницы фактически отображаются как верхний уровень windows.

Когда виджет добавляется в макет, он становится его владельцем; если макет уже настроен на виджет, то виджет, который был добавлен в макет, становится родителем другого. То же самое произойдет, если вы установите макет , а затем .

Почему первая страница отображается как отдельное окно? И почему не показывает второе? Когда новый виджет создается без родителя, он становится окном верхнего уровня; когда виджет добавляется к новому составному макету, Qt автоматически пытается его показать; вы не установили макет ни на что (что изменило бы его, как объяснялось ранее), и в результате первая страница отображается как отдельное окно.

Теперь, поскольку первый "экран" чтобы он отображался только в первый раз, вы можете установить этот виджет как центральный виджет, а затем установить экземпляр Xyz (который на самом деле является подклассом QStackedWidget) как новый центральный виджет.

Обратите внимание, что вам не нужно использовать 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_())
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...