У меня в 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. Как я могу это исправить, чтобы мой домашний экран и экран входа в систему можно было добавить в виджет стека?






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