Jin Kwon
Jin Kwon

Reputation: 22027

How can I get paint events with 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?

Upvotes: 4

Views: 4775

Answers (2)

Pulller
Pulller

Reputation: 149

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

Upvotes: 6

Orest Hera
Orest Hera

Reputation: 6786

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?

Upvotes: 9

Related Questions