PyQt5中从子类向TabWidget添加标签时为何生成新窗口?
PyQt5 继承主窗口类后出现双窗口的问题分析
问题描述
用QtDesigner制作了带TabWidget的PyQt5 GUI,需要动态增删标签页,新标签页加载另一个QtDesigner设计的.ui文件。在MainUi类内直接实现标签创建逻辑时功能正常,但将创建逻辑移到继承MainUi的Session子类后,程序会弹出两个窗口:一个是原主窗口,另一个是带有新标签页的窗口,想明确错误原因。
正常工作的代码
from PyQt5 import QtWidgets, uic from PyQt5.QtWidgets import QMainWindow import sys class MainUi(QMainWindow): def __init__(self): super(MainUi, self).__init__() uic.loadUi('main.ui', self) # 加载主界面GUI self.show() self.sessions = [] def tabWidget_Main_AddSession(self): self.sessions.append(Session()) self.tabWidget_Main.addTab(uic.loadUi('session.ui'), 'title') # 创建包含session.ui的新标签页 class Session(): def __init__(self): super().__init__() #... 在此处理session相关逻辑 def main(): app = QtWidgets.QApplication(sys.argv) ui = MainUi() ui.tabWidget_Main_AddSession() sys.exit(app.exec_()) if __name__ == '__main__': main()
出现问题的代码
from PyQt5 import QtWidgets, uic from PyQt5.QtWidgets import QMainWindow import sys class MainUi(QMainWindow): def __init__(self): super(MainUi, self).__init__() uic.loadUi('main.ui', self) # 加载主界面GUI self.show() self.sessions = [] def tabWidget_Main_AddSession(self): self.sessions.append(Session()) self.sessions[-1].add_tab() # 创建新标签页 class Session(MainUi): def __init__(self): super(Session, self).__init__() self.page = uic.loadUi('session.ui') def add_tab(self): self.tabWidget_Main.AddTab(self.page, 'title') # 创建加载.ui文件的标签页 def main(): app = QtWidgets.QApplication(sys.argv) ui = MainUi() ui.tabWidget_Main_AddSession() sys.exit(app.exec_()) if __name__ == '__main__': main()
错误原因
核心问题在于**Session类继承了MainUi,而MainUi的__init__方法中调用了self.show()**。
当创建Session实例时,会自动触发父类MainUi的构造函数,这意味着会新建一个QMainWindow实例,加载main.ui并调用show()显示窗口——这就是第二个窗口的来源。而原本的MainUi实例已经显示了一个窗口,最终就出现了双窗口的情况。
另外从设计逻辑看,Session的职责应该是管理单个标签页的业务逻辑,而非成为新的主窗口,继承MainUi本身就是设计错误。
修正方案
方案1:让Session作为普通类,关联主窗口实例
让Session不再继承MainUi,初始化时接收主窗口实例用于逻辑处理:
from PyQt5 import QtWidgets, uic from PyQt5.QtWidgets import QMainWindow, QWidget import sys class MainUi(QMainWindow): def __init__(self): super(MainUi, self).__init__() uic.loadUi('main.ui', self) self.show() self.sessions = [] def tabWidget_Main_AddSession(self): # 传入当前主窗口实例给Session session = Session(self) self.sessions.append(session) # 将session的页面添加到标签页 self.tabWidget_Main.addTab(session.page, 'title') class Session(): def __init__(self, main_window): self.main_window = main_window # 创建QWidget作为session.ui的载体 self.page = uic.loadUi('session.ui', QWidget()) # 在此添加session的业务逻辑,比如绑定按钮信号等 def main(): app = QtWidgets.QApplication(sys.argv) ui = MainUi() ui.tabWidget_Main_AddSession() sys.exit(app.exec_()) if __name__ == '__main__': main()
方案2:将Session设计为QWidget子类(推荐)
因为session.ui本质是标签页内容,直接让Session继承QWidget,加载ui文件到自身,可直接作为标签页添加:
from PyQt5 import QtWidgets, uic from PyQt5.QtWidgets import QMainWindow, QWidget import sys class MainUi(QMainWindow): def __init__(self): super(MainUi, self).__init__() uic.loadUi('main.ui', self) self.show() self.sessions = [] def tabWidget_Main_AddSession(self): session = Session() self.sessions.append(session) # 直接将Session实例作为标签页添加 self.tabWidget_Main.addTab(session, 'title') class Session(QWidget): def __init__(self, parent=None): super().__init__(parent) # 将session.ui加载到当前Session实例中 uic.loadUi('session.ui', self) # 在此处理session的逻辑,比如按钮点击事件等 def main(): app = QtWidgets.QApplication(sys.argv) ui = MainUi() ui.tabWidget_Main_AddSession() sys.exit(app.exec_()) if __name__ == '__main__': main()
内容的提问来源于stack exchange,提问作者Stéphane REY
相关产品推荐
相关产品推荐

