Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I get paint events with QtWebEngine?

Tags:

qt

qtwebengine

I extended QWebEngineView.

#ifndef MYQWEBENGINEVIEW_H
#define MYQWEBENGINEVIEW_H
#include <QWebEngineView>
class MyQWebEngineView : public QWebEngineView
{
public:
    MyQWebEngineView(QWidget *parent = 0);
    ~MyQWebEngineView();
protected:
    virtual void paintEvent(QPaintEvent *);
};
#endif // MYQWEBENGINEVIEW_H

But I can't get paintEvent(QPaintEvent *) called.

#include "myqwebengineview.h"
#include <QPaintEvent>
#include <QPainter>
#include <QWebEngineView>
#include <QWidget>

MyQWebEngineView::MyQWebEngineView(QWidget *parent):QWebEngineView(parent)
{
    qDebug() << "MyQWebEngineView(" << parent << ")";
    qDebug() << "Qt::WA_PaintOnScreen: " << testAttribute(Qt::WA_PaintOnScreen);
    //setAttribute(Qt::WA_PaintOnScreen, true);
}
MyQWebEngineView::~MyQWebEngineView()
{
}
void MyQWebEngineView::paintEvent(QPaintEvent * event)
{
    qDebug() << "paintEvent(" << event << ")";
    QWebEngineView::paintEvent(event);
    //QWidget::paintEvent(event);

    qDebug() << event->rect();
    qDebug() << event->region();
}

Can anybody please tell me what's wrong?

like image 889
Jin Kwon Avatar asked Dec 10 '22 22:12

Jin Kwon


2 Answers

Unfortunately the widget QWebEngineView does not catch almost any events (except mouse enter and exit, recently added keyboard events), for example see "[QTBUG-43602] WebEngineView does not handle mouse events".

Almost all events (like mouse move or paint) are handled by QWebEngineView child delegate of private type RenderWidgetHostViewQtDelegateWidget that is derived from QOpenGLWidget.

It is possible to catch new child of QWebEngineView of type QOpenGLWidget and to install on this child the event filter hook for all needed events.

That solution relies on undocumented structure of QWebEngineView. Thus it may be not supported by future Qt releases. However, it is usable for projects with current Qt versions. Maybe in the future some more convenient interface to catch QWebEngineView events will be implemented.

The following subclass of QWebEngineView implements that:

#ifndef WEBENGINEVIEW_H
#define WEBENGINEVIEW_H

#include <QEvent>
#include <QChildEvent>
#include <QPointer>
#include <QOpenGLWidget>
#include <QWebEngineView>
#include <QPaintEvent>

class WebEngineView : public QWebEngineView
{
    Q_OBJECT

private:
    QPointer<QOpenGLWidget> child_;

protected:
    bool eventFilter(QObject *obj, QEvent *ev)
    {
        // emit delegatePaint on paint event of the last added QOpenGLWidget child
        if (obj == child_ && ev->type() == QEvent::Paint) {
            QPaintEvent *pe = static_cast<QPaintEvent*>(ev);
            // do something with paint event
            // ...
            // or just emit signal to notify other objects
            emit delegatePaint(pe);
        }

        return QWebEngineView::eventFilter(obj, ev);
    }

public:
    WebEngineView(QWidget *parent = nullptr) :
        QWebEngineView(parent), child_(nullptr)
    {
    }

    bool event(QEvent * ev)
    {
        if (ev->type() == QEvent::ChildAdded) {
            QChildEvent *child_ev = static_cast<QChildEvent*>(ev);

            // there is also QObject child that should be ignored here;
            // use only QOpenGLWidget child
            QOpenGLWidget *w = qobject_cast<QOpenGLWidget*>(child_ev->child());
            if (w) {
                child_ = w;
                w->installEventFilter(this);
            }
        }

        return QWebEngineView::event(ev);
    }

signals:
    void delegatePaint(QPaintEvent*);
};

#endif // WEBENGINEVIEW_H

Child adding is caught by WebEngineView::event. The child pointer is saved and the event filter is installed on this child. On the child paint event the signal WebEngineView::delegatePaint(QPaintEvent*) is emitted in WebEngineView::eventFilter.

The signal delegatePaint is always emitted when the Web view is changed by some script or by highlighting of some web controls due to mouse hover or for any other reason.

Note that it is not the same as overriding QWebEngineView::paintEvent. In that way it is possible only to receive notification that something is changed.

So, it is possible to react on the event directly in WebEngineView::eventFilter or to connect to the signal delegatePaint to notify other objects about Web view repainting, for example see QT QWebEngine render after scrolling?

like image 160
Orest Hera Avatar answered Feb 04 '23 19:02

Orest Hera


My demand is disabling the mouse click. Follow Orest's answer, the "w" always is NULL in the Qt 5.9.3.

QOpenGLWidget *w = qobject_cast<QOpenGLWidget*>(child_ev->child());

So I modify the answer follow Orest. That is more suitable for Qt 5.9.x.

#ifndef CUSTOMWEBVIEW_H
#define CUSTOMWEBVIEW_H

#include <QWebEngineView>
#include <QOpenGLWidget>
#include <QDebug>
#include <QEvent>

class CustomWebView : public QWebEngineView
{
    Q_OBJECT

public:
    CustomWebView(QWidget* parent = Q_NULLPTR);

protected:
    bool event(QEvent* evt)
    {
        qDebug() << evt->type();

        if (evt->type() == QEvent::ChildPolished)
        {
            QChildEvent *child_ev = static_cast<QChildEvent*>(evt);
            childObj = child_ev->child();

            if (childObj)
            {
                childObj->installEventFilter(this);
            }
        }

        return QWebEngineView::event(evt);
    }

    bool eventFilter(QObject *obj, QEvent *ev)
    {
        if (obj == childObj
                && (ev->type() == QEvent::MouseButtonPress
                    || ev->type() == QEvent::MouseButtonDblClick))
        {
            return true;
        }

        return QWebEngineView::eventFilter(obj, ev);
    }

private:
    QObject *childObj = NULL;
};

#endif // CUSTOMWEBVIEW_H
like image 21
Pulller Avatar answered Feb 04 '23 21:02

Pulller