Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

QWebEngineView fails to access through sender()



  • Hi. I'm trying to render PDF with PDF.js using QWebEngineView.
    I've already managed to do it on the main screen, but I'd like to have some thumbpics.
    So I'm connecting the signal loadfinished to a slot that would render site to a QPixmap and then push it into the layout as a button.

    The thing is that when I try to access the view on the slot I get a SIGSEV error, which according to the debugger originates on QWidget *QWebEnginePage::view() const, called by the " web_eng->page()->view()->render(&painter);" line of my code.

    I'm aware that the thumbpic is going to have a bad size and that addWidget is not threadsafe. I was planning to address that later. My tests are done with a single QDir

    void mainwindow::generate_thumbpics (std::vector<QDir> &pdf_paths) {
        static QString pathToPDFjs = QString("qrc:/pdf_js/pdf_js/web/viewer.html");
        for (const QDir &dir : pdf_paths) {
            QString instruccion = pathToPDFjs + QString("?file=") +
                                  "file://" + dir.absolutePath();
    
            QWebEngineView *web_eng = new QWebEngineView (nullptr);
            QObject::connect(web_eng->page(), &QWebEnginePage::loadFinished,
                             this, &factura_viewer::push_thumbpic);
    
            web_eng->setAttribute(Qt::WA_DontShowOnScreen);
            web_eng->load(QUrl::fromUserInput(instruccion));
            web_eng->show();
        }
    }
    
    void mainwindow::push_thumbpic() {
        if (sender()) {
            QWebEngineView *web_eng = (QWebEngineView*)sender();
    
            QPushButton* retorno = new QPushButton;
            QPixmap *pix = new QPixmap (500, 500);
            QPainter painter (pix);
            web_eng->page()->view()->render(&painter);
            painter.end();
    
            retorno->setIcon(*pix);
            this->ui->tab_perf_fac->layout()->addWidget(retorno);
    
            delete web_eng;
        }
    }
    


  • Hi,

    I'm suspicious about this:

    QWebEngineView *web_eng = (QWebEngineView*)sender();
    

    I 'd rather do :

    QWebEngineView *web_eng = qobject_cast<QWebEngineView*>(sender());
    
    if(web_eng == nullptr)
      {
      // error
      return;
      }
    

    And according to this:

    QObject::connect(web_eng->page(), &QWebEnginePage::loadFinished,
    

    it seems obvious that sender() is not a WebView :)



  • The sender() is the object that emits the signal, and in this case it is not the QWebEngineView but the QWebEnginePage, so in your case the code should be:

    void mainwindow::push_thumbpic() {
        if (QWebEnginePage *page = qobject_cast<QWebEnginePage *>(sender()) {
            QPushButton* retorno = new QPushButton;
            QPixmap pix(500, 500);
            QPainter painter(&pix);
            page->view()->render(&painter);
            painter.end();
    
            retorno->setIcon(pix);
            this->ui->tab_perf_fac->layout()->addWidget(retorno);
    
            page->view()->deleteLater();
        }
    }
    

    Or change

    QObject::connect(web_eng->page(), &QWebEnginePage::loadFinished,  this, &factura_viewer::push_thumbpic);
    

    to

        connect(web_eng, &QWebEngineView::loadFinished, this, &factura_viewer::push_thumbpic);
    // ...
    void mainwindow::push_thumbpic() {
        if (QWebEngineView *view = qobject_cast<QWebEngineView *>(sender()) {
            QPushButton* retorno = new QPushButton;
            QPixmap pix(500, 500);
            QPainter painter(&pix);
            view->render(&painter);
            painter.end();
    
            retorno->setIcon(pix);
            this->ui->tab_perf_fac->layout()->addWidget(retorno);
    
            view->deleteLater();
        }
    }
    


  • oh my god! I can't believe i was so blind! Thanks a lot to both!

    I switched the connection back to QWebEngineView. I don't even remember why I thought that sending the signal from QWebEnginePage was a good idea, since i have to delete the pointer not to let it hanging.

    Now it seems to work, but pix comes out blank. Perhaps loadfinished is too quick, and triggers before javascript has finished generating the document?

    Is there a slower signal? Or perhaps a way to give js a tad more of time to load before calling render? Before using signals and slots I tried to wait it with a loop, but it seems the loop blocks js.