提问人:sonovice 提问时间:8/28/2016 最后编辑:ekhumorosonovice 更新时间:10/18/2023 访问量:1112
QWebEngineView 无法使用 setHtml 加载大型 SVG/HTML
QWebEngineView cannot load large SVG/HTML using setHtml
问:
我尝试了两种不同的方法来在 PyQt 中加载和显示 SVG 文件:
import sys
from PyQt5.QtWebEngineWidgets import QWebEngineView
from PyQt5.QtWidgets import QApplication
from PyQt5.QtCore import QUrl
app = QApplication(sys.argv)
webView = QWebEngineView()
# Variant 1: Reasonably fast
webView.load(QUrl('file:///Test.svg'))
# Variant 2: Slow for small files, not working for big ones
webView.setHtml('<svg>........')
webView.show()
sys.exit(app.exec_())
第一种方法工作正常,但需要文件作为输入。不过,我想动态生成 SVG,所以这不是一个真正的选择。有谁知道为什么第二种方法对于更复杂的矢量图像如此缓慢或完全失败?
答:
4赞
ekhumoro
8/28/2016
#1
更新:
此问题的解决方法是使用自定义 url 方案处理程序,该处理程序无需通过 data-url 传入文件内容。
下面是一个基本演示,展示了如何实现这一点。这适用于 PyQt5 和 PyQt6(只需修改导入):
from PyQt5.QtCore import (
QUrl, QByteArray, QBuffer, QIODevice,
)
from PyQt5.QtWidgets import (
QApplication, QWidget, QPushButton, QCheckBox, QGridLayout,
)
from PyQt5.QtWebEngineCore import (
QWebEngineUrlScheme, QWebEngineUrlSchemeHandler, QWebEngineUrlRequestJob,
)
from PyQt5.QtWebEngineWidgets import QWebEngineView
HTML_DATA = {}
URL_SCHEME = 'local'
TEST_FILE = 'test.data'
class UrlSchemeHandler(QWebEngineUrlSchemeHandler):
def requestStarted(self, job):
href = job.requestUrl().path()
if (data := HTML_DATA.get(href)) is not None:
if not isinstance(data, bytes):
data = str(data).encode()
mime = QByteArray(b'text/html')
buffer = QBuffer(job)
buffer.setData(data)
buffer.open(QIODevice.OpenModeFlag.ReadOnly)
job.reply(mime, buffer)
else:
print(f'ERROR: request job failed: {href!r}')
job.fail(QWebEngineUrlRequestJob.Error.UrlNotFound)
class Window(QWidget):
def __init__(self):
super().__init__()
self.button = QPushButton('Load Source')
self.button.clicked.connect(self.handleButtton)
self.option = QCheckBox('Use url scheme handler')
self.view = QWebEngineView()
self.view.page().profile().installUrlSchemeHandler(
bytes(URL_SCHEME, 'ascii'), UrlSchemeHandler(self))
self.view.loadFinished.connect(self.handleLoaded)
layout = QGridLayout(self)
layout.addWidget(self.view, 0, 0, 1, 2)
layout.addWidget(self.button, 1, 0)
layout.addWidget(self.option, 1, 1)
def handleButtton(self):
if self.option.isChecked():
url = QUrl(TEST_FILE)
url.setScheme(URL_SCHEME)
self.view.setUrl(url)
else:
self.view.setHtml(HTML_DATA[TEST_FILE])
def handleLoaded(self, ok):
if not ok:
self.view.setHtml('<h3>414: URI Too Long</h3>')
if __name__ == '__main__':
try:
HTML_DATA[TEST_FILE] = open('large.svg').read()
except OSError:
HTML_DATA[TEST_FILE] = (html := f"""
<html><head></head><body>
<h3>Test Page ({{}} MB)</h3>{'''<p>
Lorem ipsum dolor sit amet, consectetur adipiscing
elit, sed do eiusmod tempor incididunt ut labore et
dolore magna aliqua. Ut enim ad minim veniam, quis
nostrud exercitation ullamco laboris nisi ut aliquip
ex ea commodo consequat. Duis aute irure dolor in
reprehenderit in voluptate velit esse cillum dolore
eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia
deserunt mollit anim id est laborum.
</p>''' * 4000}</body></html>"""
).format(round(len(html) / 1e6, 1))
scheme = QWebEngineUrlScheme(bytes(URL_SCHEME, 'ascii'))
scheme.setFlags(QWebEngineUrlScheme.Flag.SecureScheme |
QWebEngineUrlScheme.Flag.LocalScheme |
QWebEngineUrlScheme.Flag.LocalAccessAllowed)
QWebEngineUrlScheme.registerScheme(scheme)
app = QApplication(['Test'])
window = Window()
window.setGeometry(600, 50, 800, 600)
window.show()
app.exec()
上一个答案:
该函数无法加载任何大小大于 2MB 的内容(不仅仅是 svg)。这是因为 Chromium 使用方案 url 来加载内容(这会将 url 的大小限制为最大长度)。因此,似乎唯一的选择是从本地文件加载svg。setHtml
data:
- 请参见:QTBUG-53414
评论
0赞
sonovice
8/29/2016
这很不幸,但好吧......谢谢你的解释。
评论