我的
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
屏幕是从PyQt5 Designer生成的*.ui
文件生成的。当我运行此代码时,出现此错误:
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
是 form 类(从根本上来说,基本的 Python 对象)而不是小部件;setupUi(self)
是没有意义的,因为它会重写当前小部件的UIsetCentralWidget()
将自动销毁之前设置的小部件,这对于堆叠小部件的目的来说显然是错误的,因为它应该允许切换回之前显示的“页面”;将堆叠的小部件作为中央小部件,然后创建适当的 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 元素作为实例属性,从而避免了对进一步
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)
)
在上面的代码中,差异似乎很小(有争议的是毫无意义和不必要的冗长),但关键是为每个页面或容器小部件创建子类允许正确且更简单的实现和调试(请参阅封装),例如可能性添加自定义信号、创建内部函数并简化对对象属性的访问。