我有一个应用程序需要使用QWebView::setContent()
将一些HTML内容加载到QWebView。所有这些都发生在带有ARMv5处理器(想想400 MHz(的嵌入式设备上。大多数情况下,我可以在合理的时间内(最多 5 秒(加载页面,但有时我的内容需要很长时间才能加载(30KB 的内容需要 ~30 秒(。
问题是setContent
调用阻塞了主线程。我需要能够在加载期间处理事件,如果用户决定不再等待,我甚至可以取消加载。
我正在考虑在其他线程中运行 setContent
调用,这样它就不会阻塞事件处理,如有必要,我可以取消它。但是,我得到了可怕的"必须在 GUI 线程中创建小部件",我认为没有办法轻松解决这个问题。
是否可以在单独的线程中运行QWebView::setContent
?如果是这样,如何?如果不是,是否可以在setContent
运行时处理 GUI 事件?是否可以"取消"setContent
通话?
编辑
为了澄清更多,我真正感兴趣的是如何能够停止setContent
调用和/或处理 GUI 消息,以便界面保持响应,使用 setContent
传递大量数据。
编辑 2
为了进一步澄清,我正在处理长而静态的内容,即没有JavaScript,只有大量的静态HTML,即使加载更多内容,用户也希望通过这些内容滚动。主要思想是允许她/他进入页面,即使页面没有完全加载。
前段时间我遇到了类似的问题。据我所知,只有页面的主要内容是同步运行的。
事实是 GUI 核心"绘制"页面,这很耗时。因此,主线程被冻结,直到主要内容完全加载。
就我而言,解决方案很简单:使主要内容成为次要内容并使用本地文件!!
那么,我的建议是什么:
1( 准备一个包含以下内容的本地文件 ( /tmp/loader.html
(:
<html>
<body onload='setTimeout(function() { window.location="contents.html"; }, 1000);'>
Loading...
</body>
</html>
2(每次需要加载新内容时,将其保存到辅助文件(/tmp/contents.html
(并强制更新加载程序(也可能是刷新(。容易:
QFile f("/tmp/contents.html");
if (f.open(QFile::WriteOnly)) {
qint64 pos = 0;
while (pos < contents.length()) {
pos += f.write(contents.mid(pos, 1024)); // chunk of 1024
qApp->processEvents();
}
f.close();
webview->setUrl(QUrl::fromLocalFile("/tmp/loader.html"));
}
观察我允许事件循环处理挂起的事件,如果文件保存也很慢......
3(每当您需要取消加载时,都可以加载其他内容,删除内容文件或其他可能的方法。
请注意,据我所知,您永远不会异步绘制内容。这才是嵌入式系统中真正的问题。
由于QWebView::setContent()
是一个阻塞调用,我最终使用了解决方法。主要思想是 XML 处理比呈现页面快得多。因此,我执行以下操作:
- 将文档解析为 XML DOM 文档(在我的情况下是一个合理的假设(,并找到
body
元素。 - 仅保留预定义数量的
body
子元素(大约 20 个元素(。将其余元素存储在另一个 XML DOM 文档中。 - 使用
QWebView::setContent()
显示初始文档(序列化 XML(,相对较快。在SLOT(loadNextChunk())
上启动超时为 0 的计时器。 -
loadNextChunk()
使用body->appendInside(html)
从正文末尾的备份文档中移动另外 20 个左右的元素,其中body
是一个QWebElement
。 - 当没有更多元素可用时停止。
这是有效的,因为在调用loadNextChunk()
之间,GUI有机会对事件做出反应。
顾名思义,QWebView是一个小部件。另一方面,QWebPage是一个普通的旧QObject,具有您可能想要的所有线程优势。
现在把它绑在一起:
void QWebView::setPage ( QWebPage * page )