PyQtWebEngine多窗口重复绘图无报错崩溃问题排查与修复方案咨询
解决PyQtWebEngine多窗口/重复绘图无报错崩溃问题
我之前遇到过几乎一模一样的PyQtWebEngine稳定性问题,结合你的代码场景和版本信息,下面几个方向应该能彻底解决你的崩溃问题:
1. 修复子窗口生命周期管理问题
你当前打开子窗口时用的是局部变量,Python的垃圾回收(GC)可能会在你没注意到的时候回收这些窗口实例,导致无预警崩溃。另外,直接把主窗口设为子窗口父类时,WebEngine的资源共享逻辑可能触发Qt的底层bug。
修改main_form的子窗口创建逻辑,手动管理子窗口实例:
class main_form(QtWidgets.QMainWindow): def __init__(self, username, password, parent=None): super().__init__(parent) self.ui = uic.loadUi(os.path.abspath('source/main_form.ui'), self) self.setGeometry(300, 300, 1150, 574) # 维护子窗口实例列表,防止被GC回收 self.sub_windows = [] def open_sample_window(self, item): # ...(获取sample_id逻辑) sample_window = sub_form(string, string, string, string, parent=self) sample_window.show() self.sub_windows.append(sample_window) # 子窗口销毁时从列表移除,避免内存泄漏 sample_window.destroyed.connect(lambda win: self.sub_windows.remove(win))
2. 把耗时操作移到子线程,避免阻塞UI主线程
你的SFTP文件读取、Plotly绘图都是耗时操作,直接在UI线程执行会导致主线程阻塞,触发WebEngine的资源死锁或崩溃。用QThread把这些操作剥离出去:
from PyQt5.QtCore import QThread, pyqtSignal class PlotWorker(QThread): plot_ready = pyqtSignal(str) error_occurred = pyqtSignal(str) def __init__(self, sftp_conn, remote_path): super().__init__() self.sftp_conn = sftp_conn self.remote_path = remote_path def run(self): try: with self.sftp_conn.open(self.remote_path, "r") as f: f.readline() # 跳过condition行 df = pd.read_csv(f, delim_whitespace=True, names=["2Theta", "peak"]) if len(df) > 0: fig = px.line(df, x="2Theta", y="peak") fig.update_layout( xaxis_title="2Theta", yaxis_title="peak", template='plotly_white' ) self.plot_ready.emit(fig.to_html(full_html=False)) else: self.plot_ready.emit("<p>No data available</p>") except Exception as e: self.error_occurred.emit(f"Failed to generate plot: {str(e)}") class sub_form(QtWidgets.QMainWindow): def __init__(self, *args, parent=None): super().__init__(parent) self.ui = uic.loadUi(os.path.abspath('source/Sample_form.ui'), self) self.current_worker = None def result_file_list_view_double_clicked(self, index=None): # ...(获取远程文件路径逻辑) # 先终止正在运行的任务,避免资源冲突 if self.current_worker and self.current_worker.isRunning(): self.current_worker.quit() self.current_worker.wait() self.current_worker = PlotWorker(self.sftp_connection_open(), full_remote_file_name) self.current_worker.plot_ready.connect(self.update_plot) self.current_worker.error_occurred.connect(self.show_error) self.current_worker.start() def update_plot(self, html): self.result_plot_view.setHtml(html) def show_error(self, msg): self.result_plot_view.setHtml(f"<p style='color:red'>{msg}</p>") def closeEvent(self, event): # 关闭窗口时清理线程资源 if self.current_worker and self.current_worker.isRunning(): self.current_worker.quit() self.current_worker.wait() super().closeEvent(event)
3. 升级PyQtWebEngine到稳定版本
你用的PyQtWebEngine 5.15.2/3/4存在已知的多窗口内存泄漏和崩溃bug,Qt官方在5.15.10版本修复了大部分这类问题。执行以下命令升级:
pip install --upgrade PyQtWebEngine==5.15.10 PyQt5==5.15.10
注意要保证PyQt5和PyQtWebEngine版本完全一致,否则会出现兼容性问题。
4. 启用调试工具定位剩余问题
如果还是出现崩溃,启用Python的故障处理器捕获崩溃堆栈:
import faulthandler faulthandler.enable()
同时设置环境变量QT_LOGGING_RULES="qt.webengine.debug=true",启动程序后会输出WebEngine的详细调试日志,帮你找到具体的崩溃触发点。
内容的提问来源于stack exchange,提问作者Jaeho Song
相关产品推荐
相关产品推荐

