嵌套函数内修改的实例属性无法传递至外部的技术求助
嵌套鼠标事件函数修改实例变量后无法在子类中正确访问的问题
问题现象
- 在Qt+Matplotlib的GUI开发中,通过
on_motion鼠标事件触发的嵌套函数内修改了MainWindow的实例变量self.hub_bezier_line,但子类SecondWindow访问该变量时,获取到的是初始值而非修改后的值。 - 具体表现:左侧画布的贝塞尔曲线更新正常,但右侧子类窗口的图表始终绘制初始值;保存的
hub1(初始值)和hub3(子类中获取的值)完全一致,hub2(鼠标修改后的值)是正确的更新结果。

问题代码
class MainWindow(QtWidgets.QMainWindow): def __init__(self): super().__init__() uic.loadUi('Bezier_fit.ui', self) self.shroud_bezier_line, self.hub_bezier_line = bezier_point(self.inter_point, self.ctr_point) # np.savetxt("hub1",self.hub_bezier_line) self.bezier_line.clicked.connect(lambda: self.set_ctr_point()) def set_ctr_point(self): def on_motion(event): if dragging and event.inaxes == self.plotCanvas_bezier.ax: self.ctr_point = renew_data(self.ctr_point, event.xdata, event.ydata, current_index) self.shroud_bezier_line,self.hub_bezier_line=bezier_point(self.inter_point, self.ctr_point) # np.savetxt("hub2",self.hub_bezier_line) cid_motion = self.plotCanvas_bezier.ax.figure.canvas.mpl_connect('motion_notify_event', on_motion) class SecondWindow(MainWindow): def __init__(self): super().__init__() uic.loadUi('streamline.ui', self) # np.savetxt("hub3",self.hub_bezier_line)
解决方案
1. 修正子类继承逻辑(核心问题)
你的SecondWindow继承MainWindow后,调用super().__init__()会重新执行父类的初始化流程,包括重新计算self.hub_bezier_line为初始值,直接覆盖了之前鼠标修改的结果。
解决方式:不要让SecondWindow继承MainWindow,改为通过实例传递共享数据:
# 修改SecondWindow定义 class SecondWindow(QtWidgets.QMainWindow): def __init__(self, main_window): super().__init__() uic.loadUi('streamline.ui', self) # 直接从主窗口实例获取最新数据 self.hub_bezier_line = main_window.hub_bezier_line
启动SecondWindow时传入主窗口实例:
# 在MainWindow的某个触发逻辑中打开SecondWindow def open_second_window(self): self.second_win = SecondWindow(self) self.second_win.show()
2. 用Qt信号实时同步数据
为了让SecondWindow能实时获取鼠标修改后的最新数据,在MainWindow中定义信号并在数据更新时发送:
from PyQt5.QtCore import pyqtSignal class MainWindow(QtWidgets.QMainWindow): # 定义信号,传递更新后的贝塞尔曲线数据 bezier_data_updated = pyqtSignal(object, object) def __init__(self): super().__init__() uic.loadUi('Bezier_fit.ui', self) self.shroud_bezier_line, self.hub_bezier_line = bezier_point(self.inter_point, self.ctr_point) self.bezier_line.clicked.connect(self.set_ctr_point) def set_ctr_point(self): def on_motion(event): if dragging and event.inaxes == self.plotCanvas_bezier.ax: self.ctr_point = renew_data(self.ctr_point, event.xdata, event.ydata, current_index) self.shroud_bezier_line, self.hub_bezier_line = bezier_point(self.inter_point, self.ctr_point) # 发送信号通知数据更新 self.bezier_data_updated.emit(self.shroud_bezier_line, self.hub_bezier_line) cid_motion = self.plotCanvas_bezier.ax.figure.canvas.mpl_connect('motion_notify_event', on_motion)
然后在SecondWindow中连接信号,实时更新数据:
class SecondWindow(QtWidgets.QMainWindow): def __init__(self, main_window): super().__init__() uic.loadUi('streamline.ui', self) # 连接主窗口的信号 main_window.bezier_data_updated.connect(self.update_bezier_data) # 初始化获取初始数据 self.hub_bezier_line = main_window.hub_bezier_line def update_bezier_data(self, shroud_line, hub_line): self.hub_bezier_line = hub_line # 这里添加更新右侧图表的代码 self.refresh_right_plot()
3. 封装独立的数据存储类
将贝塞尔曲线数据封装到独立的类中,确保所有窗口共享同一个数据实例:
class BezierStorage: def __init__(self): self.shroud_line = None self.hub_line = None # 在程序启动时创建全局共享实例 bezier_storage = BezierStorage() # MainWindow中使用 class MainWindow(QtWidgets.QMainWindow): def __init__(self): super().__init__() uic.loadUi('Bezier_fit.ui', self) bezier_storage.shroud_line, bezier_storage.hub_line = bezier_point(self.inter_point, self.ctr_point) self.bezier_line.clicked.connect(self.set_ctr_point) def set_ctr_point(self): def on_motion(event): if dragging and event.inaxes == self.plotCanvas_bezier.ax: self.ctr_point = renew_data(self.ctr_point, event.xdata, event.ydata, current_index) bezier_storage.shroud_line, bezier_storage.hub_line = bezier_point(self.inter_point, self.ctr_point) cid_motion = self.plotCanvas_bezier.ax.figure.canvas.mpl_connect('motion_notify_event', on_motion) # SecondWindow中直接访问共享实例 class SecondWindow(QtWidgets.QMainWindow): def __init__(self): super().__init__() uic.loadUi('streamline.ui', self) self.hub_bezier_line = bezier_storage.hub_line
内容的提问来源于stack exchange,提问作者G sink
相关产品推荐
相关产品推荐

