我在我的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_homeUi_login_pageform classes(基本上,是基本的Python对象),而不是小部件;
  • 多次调用setupUi(self)是毫无意义的,因为它会重写当前小部件的UI;
  • 多次调用setCentralWidget()将自动destroy之前设置的小部件,对于堆叠小部件的目的来说,这显然是错误的,因为它应该允许切换回之前显示的"页面";

将堆叠小部件作为中心小部件,然后创建适当的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)
        )

请注意,一种更合适的方法(在关于using Designer的官方指南中也解释了)是使用multiple inheritance来对抗composition(这是上面所示的);该方法提供了更好的模块化,因 for each "页面"都将有自己的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)
        )

在上面的代码中,差异似乎很小(有争议地既毫无意义,又不必要地冗长),但重点是, for each 页面或容器小部件创建一个子集允许适当且更简单的实现和调试(参见encapsulation),例如添加自定义信号的可能性、创建内部函数,并简化对对象属性的访问.

Python相关问答推荐

我们可以只打印一次循环中的文本,而不让它一遍又一遍地打印直到循环结束吗?

这些变量是否相等,因为它们引用相同的实例,尽管它们看起来应该具有不同的值?

单击Cookie横幅错误并在Selenium中启用搜索栏

是否有方法将现有的X-Y图转换为X-Y-Y1图(以重新填充)?

使用Python Great Expectations和python-oracledb

PyQt5如何将pyuic 5生成的Python类添加到QStackedWidget中?

通过仅导入pandas来在for循环中进行多情节

在Python和matlab中显示不同 colored颜色 的图像

Gekko:Spring-Mass系统的参数识别

类型错误:输入类型不支持ufuncisnan-在执行Mann-Whitney U测试时[SOLVED]

运行总计基于多列pandas的分组和总和

如何使用html从excel中提取条件格式规则列表?

Telethon加入私有频道

Python解析整数格式说明符的规则?

在Python argparse包中添加formatter_class MetavarTypeHelpFormatter时, - help不再工作""""

启用/禁用shiny 的自动重新加载

在www.example.com中使用`package_data`包含不包含__init__. py的非Python文件

在两极中过滤

如何在TensorFlow中分类多个类

在pandas数据框中计算相对体积比指标,并添加指标值作为新列