首页 > 解决方案 > 如果 QApplication 执行延迟,QWebEngineView 在加载内容时会静默失败

问题描述

我们正在开发一个带有 Qt UI 的应用程序,其中包含QWebEngineView. 目前正在使用 Qt 5.9.6 在 macOS (10.12..10.14) 上进行测试

由于操作系统的特殊性,应用程序有时会等待用户输入(例如系统管理员密码),然后才能到达QApplication::exec(). 我们意识到,如果等待时间过长,QWebEngineView::load(QUrl)调用会默默地失败,显示灰色视图而不是预期的呈现 html。

我们创建了一个最小示例,在我们的测试环境中触发问题:

#include <QApplication>
#include <QMainWindow>
#include <QWebEngineView>
#include <QWidget>

#include <chrono>    
#include <iostream>
#include <thread>

int main(int argc, char *argv[])
{
    QApplication qtapp(argc, argv);

    QMainWindow *window = new QMainWindow;
    window->setFixedSize({800, 600});
    QWebEngineView *webview = new QWebEngineView();
    window->setCentralWidget(webview);

    window->show();

    std::this_thread::sleep_for(std::chrono::seconds(30));
    std::clog << "Done sleeping" << std::endl;

    webview->load({"https://www.google.com"});

    return qtapp.exec();
}

注释掉sleep谷歌主页就可以了。有了sleep,我们得到了灰色区域。


编辑:进一步调查表明,只要在和sleep之前,问题就不会发生。webview->load()window->show()

标签: c++qt5qtwebengine

解决方案


Qt 有一个事件循环,允许您监视各种事件,例如键盘、鼠标等将它分成更少的任务 如果我们可以的话称重它们或者在一个新线程中执行它并通过信号将结果传输到 GUI 线程。在下面的示例中,我展示了一个简单的实现。

#include <QtWebEngineWidgets>
#include <iostream>

class Worker: public QObject
{
    Q_OBJECT
public:
    using QObject::QObject;
public slots:
    void start_task(){
        std::this_thread::sleep_for(std::chrono::seconds(30));
        std::clog << "Done sleeping" << std::endl;
        emit finished();
    }
signals:
    void finished();
};

class Thread final : public QThread {
    Q_OBJECT
public:
    using QThread::QThread;
    ~Thread() override {
        finish(); wait();
    }
public slots:
    void finish() {
        quit(); requestInterruption();
    }
};

int main(int argc, char *argv[])
{
    QApplication qtapp(argc, argv);
    QMainWindow window;
    window.setFixedSize({800, 600});
    QWebEngineView *webview = new QWebEngineView();
    window.setCentralWidget(webview);
    window.show();
    Thread thread;
    QObject::connect(QApplication::instance(), &QApplication::aboutToQuit, &thread, &Thread::finish);
    thread.start();
    Worker worker;
    worker.moveToThread(&thread);
    QObject::connect(&worker, &Worker::finished, webview, [webview](){
        qDebug()<< "finished";
        webview->load({"https://www.google.com"});
    });
    QMetaObject::invokeMethod(&worker, "start_task", Qt::QueuedConnection);
    return qtapp.exec();
}
#include "main.moc"

推荐阅读