Question

I have an application that requires to use QWebView::setContent() to load some HTML content to a QWebView. All of this happens on an embedded device with ARMv5 processor (think 400 MHz). Most of the time, I can load the page in reasonable time (up to 5 seconds), however sometimes I have content that takes long time to load (~30 seconds for 300KB of content).

The problem is that the setContent call blocks the main thread. I need to be able to process events during the loading, and maybe even cancel the load if the user decides not to wait any longer.

I was thinking about running the setContent call in other thread, so that it does not block the event processing and I can cancel it if necessary. However, I get the dreaded "widgets must be created in the GUI thread", and I see no way of solving this easily.

Is it possible to run QWebView::setContent in a separate thread? If so, how? If not, is it possible to handle GUI events while setContent is running? Is it possible to "cancel" the setContent call?

EDIT

To clarify a bit more, what really interests me is how to be able to stop the setContent call and/or handle GUI messages, so that the interface remains responsive, with large amounts of data passed using setContent.

EDIT 2

To clarify even further, I am dealing with long, static content, i.e. no JavaScript, just a lot of static HTML, through which the user wants to scroll even while it is loading more content. The main idea is to allow her/him to go down a page even when the page is not fully loaded.

Was it helpful?

Solution 2

Since QWebView::setContent() is a blocking call, I ended up using a work-around. The main idea is that XML processing is much faster than rendering the page. Therefore I do the following:

  1. Parse the document as XML DOM document (a reasonable assumption in my case), and find the body element.
  2. Keep only a pre-defined number of child elements of body (something like 20 elements). Store the remaining elements in another XML DOM document.
  3. Show the initial document (serialized XML) using QWebView::setContent(), which is relatively fast. Start a timer with timeout 0 on SLOT(loadNextChunk()).
  4. loadNextChunk() moves another 20 or so elements from the backup document at the end of the body using body->appendInside(html), where body is a QWebElement.
  5. Stop when no more elements are available.

This works because in between the calls to loadNextChunk(), the GUI has a chance to react to events.

OTHER TIPS

Some time ago I faced a similar problem. As far as I know, only the main contents of the page is acting synchronously.

The fact is that the GUI core "paints" the page and this is time consuming. So, the main thread gets freezed until the main contents is loaded completely.

In my case, the solution was simple: make the main contents a secondary one and work with local files!!!

So, what is my proposal:

1) Prepare a local file (/tmp/loader.html) that contains something like this:

<html>
<body onload='setTimeout(function() { window.location="contents.html"; }, 1000);'>
Loading...
</body>
</html>

2) Each time you need to load a new content, save it to the secondary file (/tmp/contents.html) and force the update of the loader (maybe also a refresh). Easy:

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"));
}

Observe that I permit the event loop to process pending events if the file saving is also slow...

3) Anytime you need to cancel the loading, you can load another contents, remove the contents file, or other possible approaches.

Note that, as far as I know, you would never make asynchronous the painting of the contents. And that is the real issue in embedded systems.

QWebView, as its name suggests, is a widget. QWebPage, on the other hand, is a plain old QObject, with all the threading goodness you could possibly want.

Now tie it together:

void QWebView::setPage ( QWebPage * page )
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top