c++qtc++11lambdaqwebpage

get HTML from QWebEnginePage in QWebEngineView using Lamda


I want to get the HTML code of a web page opened in QWebEngineView I use toHtml() function in QWebEnginePage Class like this

QWebEnginePage *page = ui->widget->page();
QString HTML = "";
page->toHtml([&HTML](QString html){qDebug() << "code \n\n\n" << html;});

the HTML code of html page appeared in qDebug good without problem the problem here is when I want to use HTML string outside the function when I show the size of the HTML varible it is equal to zero and empty so I tried this

QWebEnginePage *page = ui->widget->page();
QString HTML = "";
page->toHtml([&HTML](QString html){HTML = html;}); // crash
qDebug() << "i want to use HTML here outside the function = " << HTML;

but the app crash show so what should I do so I put the HTML data in the HTML variable so I can use it outside the function
Thanks in advance


Solution

  • Your problem is caused by the fact that the lambda is run asynchronously. So it is really called after you have exited the method in which you call toHtml method and that also explains the crash - HTML is a local variable within the method which has already exited so the lambda just randomly corrupts the memory used to be occupied by HTML variable.

    What you want to do here is to synchronize things i.e. block your method until the lambda is executed. It can be done with QEventLoop but that would need to involve sending a special signal from the lambda to indicate the fact that the lambda finished executing. So it would look somewhat like this (non-tested):

    class MyClass: public QObject
    {
        Q_OBJECT
    public:
        MyClass(QWebEnginePage & page, QObject * parent = 0);
    
        void notifyHtmlReceived();
    
        QString getHtml();
        void setHtml(const QString & html) { m_html = html; }
    
    Q_SIGNALS:
        void htmlReceived();
    
    private Q_SLOTS:
        void requestHtmlFromPage();
    
    private:
        QWebEnginePage & m_page;
        QString m_html;
    };
    
    MyClass::MyClass(QWebEnginePage & page, QObject * parent) :
        QObject(parent),
        m_page(page)
    {}
    
    void MyClass::notifyHtmlReceived()
    {
        emit htmlReceived();
    }
    
    QString MyClass::getHtml()
    {
        QEventLoop loop;
        QObject::connect(this, SIGNAL(htmlReceived()), &loop, SLOT(quit()));
    
        // Schedule the slot to run in 0 seconds but not right now
        QTimer::singleShot(0, this, SLOT(requestHtmlFromPage()));
    
        // The event loop would block until the lambda receiving the HTML is executed
        loop.exec();
    
        // If we got here, the html has been received and the result was saved in m_html
        return m_html;   
    }
    
    void MyClass::requestHtmlFromPage()
    {
        m_page.toHtml([this](QString html)
                      {
                          this->setHtml(html);
                          this->notifyHtmlReceived();
                      });
    }