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

PyQt浏览器下载管理器点击开始按钮触发RuntimeError问题求助

问题

开发了一款基于PyQt的网页浏览器,需求为点击下载链接时弹出下载管理窗口,在该窗口中实现下载任务的启动与停止控制。但点击下载管理窗口的开始按钮时,出现错误:
RuntimeError: wrapped C/C++ object of type QWebEngineDownloadItem has been deleted

原代码

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtWebEngineWidgets import *
import os
import sys
from functools import partial

class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.browser = QWebEngineView()
        self.browser.page().profile().downloadRequested.connect(self.openDownloadManagerWindow)
        self.browser.setUrl(QUrl("http://google.com"))
        self.setCentralWidget(self.browser)
        navtb = QToolBar("Navigation")
        self.addToolBar(navtb)
        self.urlbar = QLineEdit()
        self.urlbar.returnPressed.connect(self.navigate_to_url)
        navtb.addWidget(self.urlbar)
        self.show()
 
    
    #download manager window
    def openDownloadManagerWindow(self , download):
        self.downloadWindow = QDialog()
        self.downloadWindow.resize(400,200)
        self.start_button = QPushButton("Start" , self.downloadWindow)
        self.stop_button = QPushButton("Stop" , self.downloadWindow)
        self.stop_button.move(320,0)
        self.downloadWindow.show()

        self.start_button.clicked.connect(partial(self.start , download))

    def start(self , download):
        download.accept()

    def navigate_to_url(self):
        q = QUrl(self.urlbar.text())
        if q.scheme() == "":
            q.setScheme("http")
        self.browser.setUrl(q)

 

app = QApplication(sys.argv)
window = MainWindow()
app.exec_()

原因分析

这个错误的核心原因是:QWebEngineDownloadItem对象在downloadRequested信号的处理函数执行完毕后,会被Qt内部机制自动销毁——因为没有Python层面的强引用持有它。当你点击开始按钮时,尝试访问已经被销毁的C++对象,就会触发该RuntimeError。

解决方法

需要在Python代码中保留QWebEngineDownloadItem对象的引用,防止其被过早销毁。同时可以把下载管理窗口封装成独立类,让它负责持有下载对象并处理启停逻辑,代码结构更清晰。

修改后的代码

from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtWebEngineWidgets import *
import sys

class DownloadManagerWindow(QDialog):
    def __init__(self, download, parent=None):
        super().__init__(parent)
        self.download = download  # 持有下载对象引用,避免被销毁
        self.resize(400, 200)
        
        self.start_button = QPushButton("Start", self)
        self.stop_button = QPushButton("Stop", self)
        self.stop_button.move(320, 0)
        
        self.start_button.clicked.connect(self.start_download)
        self.stop_button.clicked.connect(self.stop_download)
        
        # 下载完成或取消时自动关闭窗口
        self.download.finished.connect(self.close)

    def start_download(self):
        if not self.download.isFinished():
            self.download.accept()
            self.start_button.setEnabled(False)  # 启动后禁用开始按钮

    def stop_download(self):
        if not self.download.isFinished():
            self.download.cancel()
            self.start_button.setEnabled(True)  # 取消后重新启用开始按钮

class MainWindow(QMainWindow):
    def __init__(self, *args, **kwargs):
        super(MainWindow, self).__init__(*args, **kwargs)

        self.browser = QWebEngineView()
        self.browser.page().profile().downloadRequested.connect(self.open_download_manager)
        self.browser.setUrl(QUrl("http://google.com"))
        self.setCentralWidget(self.browser)
        
        navtb = QToolBar("Navigation")
        self.addToolBar(navtb)
        
        self.urlbar = QLineEdit()
        self.urlbar.returnPressed.connect(self.navigate_to_url)
        navtb.addWidget(self.urlbar)
        
        self.show()
 
    def open_download_manager(self, download):
        # 创建下载管理窗口并传入下载对象
        self.download_window = DownloadManagerWindow(download, self)
        self.download_window.show()

    def navigate_to_url(self):
        q = QUrl(self.urlbar.text())
        if q.scheme() == "":
            q.setScheme("http")
        self.browser.setUrl(q)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    app.exec_()

关键修改点

  1. 封装下载管理窗口:创建DownloadManagerWindow类,初始化时保存QWebEngineDownloadItem对象的引用,避免Python垃圾回收和Qt内部销毁机制提前回收对象。
  2. 按钮状态控制:启动下载后禁用开始按钮,取消下载后重新启用,避免重复操作。
  3. 自动窗口关闭:关联下载完成信号,下载结束或取消时自动关闭窗口,提升用户体验。
  4. 实现停止功能:调用download.cancel()方法完成下载停止逻辑。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.19 04:07:22