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_()
关键修改点
- 封装下载管理窗口:创建
DownloadManagerWindow类,初始化时保存QWebEngineDownloadItem对象的引用,避免Python垃圾回收和Qt内部销毁机制提前回收对象。 - 按钮状态控制:启动下载后禁用开始按钮,取消下载后重新启用,避免重复操作。
- 自动窗口关闭:关联下载完成信号,下载结束或取消时自动关闭窗口,提升用户体验。
- 实现停止功能:调用
download.cancel()方法完成下载停止逻辑。
内容的提问来源于stack exchange,提问作者coder
相关产品推荐
相关产品推荐

