PyQt5 Как добавить класс Python, сгенерированный pyuic5, в QStackedWidget?

У меня в app.py есть это:

from PyQt5 import QtWidgets
from screens import Ui_home, Ui_login_page


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        
        self.home = Ui_home()
        self.home.setupUi(self)

        self.login = Ui_login_page()
        self.login.setupUi(self)
        
        self.screens = QtWidgets.QStackedWidget()
        self.screens.addWidget(self.home)
        self.screens.addWidget(self.login)

        self.home.pushButton.clicked.connect(
            lambda: self.screens.setCurrentWidget(self.login)
        )


if __name__ == '__main__':
    app = QtWidgets.QApplication([])
    window = MainWindow()
    window.show()
    app.exec_()

В приведенном выше коде экраны Ui_home и Ui_login_page генерируются из файла *.ui, созданного с помощью PyQt5 Designer. Когда я запускаю этот код, я получаю эту ошибку:

self.screens.addWidget(self.home)
TypeError: addWidget(self, w: Optional[QWidget]): argument 1 has unexpected type 'Ui_home'

Я знаю, что self.setCurrentWidget() требует QWidget, а код, сгенерированный из pyuic5, наследует класс Python object. Как я могу это исправить, чтобы мой домашний экран и экран входа в систему можно было добавить в виджет стека?

Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
0
52
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Следующие вещи неверны или не имеют смысла:

  • Ui_home и Ui_login_page — это классы форм (по сути, базовые объекты Python), а не виджеты;
  • вызывать setupUi(self) более одного раза бессмысленно, так как это перепишет пользовательский интерфейс текущего виджета;
  • вызов setCentralWidget() более одного раза автоматически уничтожит ранее установленный виджет, что явно неправильно для составного виджета, поскольку он должен позволять переключиться обратно на ранее показанную «страницу»;

Сделайте составной виджет центральным, затем создайте соответствующие экземпляры QWidget и вызовите setupUi() для каждого из них, наконец добавьте эти виджеты в составной виджет:

class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        
        self.screens = QtWidgets.QStackedWidget()
        self.setCentralWidget(self.screens)

        self.home = QtWidgets.QWidget()
        self.home_ui = Ui_home()
        self.home_ui.setupUi(self.home)

        self.login = QtWidgets.QWidget()
        self.login_ui = Ui_login_page()
        self.login_ui.setupUi(self.login)
        
        self.screens.addWidget(self.home)
        self.screens.addWidget(self.login)

        self.home_ui.pushButton.clicked.connect(
            lambda: self.screens.setCurrentWidget(self.login)
        )

Обратите внимание, что более подходящий подход (также описанный в официальных рекомендациях по использованию Designer ) — использовать множественное наследование для композиции (что показано выше); этот подход обеспечивает лучшую модульность, поскольку каждая «страница» будет иметь свои собственные элементы пользовательского интерфейса в качестве атрибутов экземпляра, что позволяет избежать необходимости в дополнительном объекте ui.

class HomePage(QtWidgets.QWidget, Ui_home):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)


class LoginPage(QtWidgets.QWidget, Ui_login_page):
    def __init__(self, parent=None):
        super().__init__(parent)
        self.setupUi(self)


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        super().__init__()
        
        self.screens = QtWidgets.QStackedWidget()
        self.setCentralWidget(self.screens)

        self.home = HomePage()
        self.login = LoginPage()
        
        self.screens.addWidget(self.home)
        self.screens.addWidget(self.login)

        # note that now it's "self.home", not "self.home_ui"
        self.home.pushButton.clicked.connect(
            lambda: self.screens.setCurrentWidget(self.login)
        )

В приведенном выше коде разница кажется минимальной (спорно, как бессмысленной, так и излишне многословной), но дело в том, что создание подкласса для каждой страницы или виджета-контейнера обеспечивает правильную и более простую реализацию и отладку (см. инкапсуляция), например возможность добавления пользовательских сигналов, создания внутренних функций и упрощения доступа к атрибутам объекта.

Другие вопросы по теме