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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 04:22:47