You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.18 09:50:51