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

PySide6子类方法中调用父类方法失败问题求助

Qt子类调用父类方法异常问题

问题描述

在子类Widget中调用父类MainWindow的do_something方法时,仅在__init__方法中调用成功,按钮点击触发的clickedInitialize方法中调用失败,报错信息如下:

AttributeError: 'PySide6.QtWidgets.QStackedWidget' object has no attribute 'do_something'

尝试代码

class MainWindow(QMainWindow):
    ws = websocket.WebSocket()
    threadpool = QThreadPool()
    pippo = "pippo"
    def __init__(self):
        super().__init__()
        tabs = QTabWidget()
        tabs.setTabPosition(QTabWidget.North)
        tabs.setMovable(False)
        tabs.setDocumentMode(True)
        self.voices = Widget("Voices", self)
        tabs.addTab(self.voices, "Voices")
        self.setCentralWidget(tabs)
    def do_something(self):
        print ('doing something!')

class Widget(QWidget):
    def __init__(self, name, parent=None):
        super().__init__(parent)
        self.ui = Ui_Widget()
        self.ui.setupUi(self)
        self.name=name
        self.lan = str(config_ini("language"))
        self.username = str(config_ini("user"))
        print(self.parent().pippo) # 此处调用成功
        self.parent().do_something()  # 此处调用成功
      
        self.ui.InitializeButton.clicked.connect(self.clickedInitialize)
        
# 点击Initialize按钮触发
    def clickedInitialize(self):
        self.parent().do_something()  # 此处调用失败

错误栈信息

Traceback (most recent call last):
  File "C:\Users\IENOGIUS\Documents\Cefla\VoiceCommands\VoiceChecker\voicechecker.py", line 294, in clickedInitialize
    self.parent().do_something()
AttributeError: 'PySide6.QtWidgets.QStackedWidget' object has no attribute 'do_something'

问题原因

Qt的父对象层级发生了变化:

  • 在Widget的__init__阶段,传入的父对象是MainWindow,此时self.parent()返回的是MainWindow实例,所以调用方法成功。
  • 当把Widget添加到QTabWidget的tab后,QTabWidget内部会自动用QStackedWidget管理所有tab页面,此时Widget的父对象被替换成了这个QStackedWidget,而非原来的MainWindow,因此调用self.parent()拿到的是没有do_something方法的QStackedWidget实例,触发报错。

解决方案

方案1:保存原始父对象

在Widget初始化时,将传入的MainWindow实例保存为自己的成员变量,后续直接通过该变量调用方法:

class Widget(QWidget):
    def __init__(self, name, parent=None):
        super().__init__(parent)
        self.main_window = parent  # 保存原始的MainWindow实例
        self.ui = Ui_Widget()
        self.ui.setupUi(self)
        self.name=name
        self.lan = str(config_ini("language"))
        self.username = str(config_ini("user"))
        print(self.main_window.pippo)
        self.main_window.do_something()
      
        self.ui.InitializeButton.clicked.connect(self.clickedInitialize)
        
    def clickedInitialize(self):
        self.main_window.do_something()  # 直接调用保存的MainWindow实例方法

方案2:获取顶层窗口对象

利用Qt的QWidget.window()方法,该方法会返回当前控件所属的顶层窗口(即MainWindow),不受中间父对象变化影响:

def clickedInitialize(self):
    self.window().do_something()

方案3:使用信号槽机制(推荐,符合Qt设计理念)

通过信号解耦子类与父类的依赖,避免直接调用父类方法:

class Widget(QWidget):
    initialize_triggered = Signal()  # 定义自定义信号

    def __init__(self, name, parent=None):
        super().__init__(parent)
        self.ui = Ui_Widget()
        self.ui.setupUi(self)
        self.name=name
        self.lan = str(config_ini("language"))
        self.username = str(config_ini("user"))
        print(self.parent().pippo)
        self.parent().do_something()
      
        self.ui.InitializeButton.clicked.connect(self.clickedInitialize)
        
    def clickedInitialize(self):
        self.initialize_triggered.emit()  # 点击按钮时发射信号

# 在MainWindow中连接信号与槽
class MainWindow(QMainWindow):
    # ... 其他代码 ...
    def __init__(self):
        super().__init__()
        tabs = QTabWidget()
        # ... 其他代码 ...
        self.voices = Widget("Voices", self)
        self.voices.initialize_triggered.connect(self.do_something)  # 绑定信号到目标方法
        tabs.addTab(self.voices, "Voices")
        self.setCentralWidget(tabs)

内容的提问来源于stack exchange,提问作者Hawke

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 21:15:34