首页 > 技术文章 > 拦截QWebView弹出窗口

dongc 2016-08-19 08:44 原文

环境

系统:win7 64位旗舰版

软件:VS2013、QT5.5.1-32位

概述

当网页打开一个新的窗口时,我们有时候需要根据URL地址来判断弹出窗口是否合理,如果合理则弹出新窗口,否则不弹出。本文假设你能够基本使用QT。

步骤

1)首先创建类InterceptNetworkAccessManager

class InterceptNetworkAccessManager : public QNetworkAccessManager {
    Q_OBJECT
public:
    InterceptNetworkAccessManager() {}

    void setIntercept(bool intercept) { m_intercept = intercept; }

signals:
    // 拦截URL信号 [8/17/2016 Chao.Dong]
    void signalInterceptUrl(const QUrl& url);

protected:
    QNetworkReply* createRequest(QNetworkAccessManager::Operation op,
        const QNetworkRequest &req,
        QIODevice *outgoingData) override {
        
        // 构造一个空的QNetworkRequest来拦截请求 [8/11/2016 Chao.Dong]
        if (m_intercept) {
            emit signalInterceptUrl(req.url());
            return QNetworkAccessManager::createRequest(op, QNetworkRequest(), outgoingData);
        }
        return QNetworkAccessManager::createRequest(op, req, outgoingData);
    }

private:
    bool m_intercept = true;
};

该类的作用是拦截网络请求,因为在创建弹出窗口时,QT没有将加载的URL地址给我们,所以我们必须先自己截获请求,因为我们的目的只是为了获取URL地址,这里构造了一个空的请求是为了减小资源消耗。

2)让后创建类HiddenWebView

/**  [8/17/2016 Chao.Dong]
 *    隐藏的web窗口
 */
class HiddenWebView : public QWebView {
    Q_OBJECT
public:
    explicit HiddenWebView(QWidget* parent = NULL) {
        QWebView::setVisible(false);
        InterceptNetworkAccessManager* network = new InterceptNetworkAccessManager();
        this->page()->setNetworkAccessManager(network);
        connect(network, SIGNAL(signalInterceptUrl(const QUrl&)), this, SIGNAL(signalInterceptUrl(const QUrl&)), Qt::QueuedConnection);
    }
    virtual void setVisible(bool visible) {}

signals:
    void signalInterceptUrl(const QUrl& url);
};

该类的作用是创建一个隐藏的web窗口,创建弹出的新窗口时,我们将隐藏web窗口给它之后,它会默认显示该窗口,而我们只是为了之后能获取新窗口的URL地址,所以并不需要显示。

3)最后创建WebView

/**  [8/9/2016 Chao.Dong]
 *    Web窗口
 */
class WebView : public QWebView {
    Q_OBJECT
public:
    explicit WebView(QWidget* parent = NULL) {
        this->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
    }

    virtual QWebView * createWindow(QWebPage::WebWindowType type) override {
        switch (type)
        {
        case QWebPage::WebBrowserWindow:

            HiddenWebView* web = new HiddenWebView();
            connect(web, &HiddenWebView::signalInterceptUrl, [this, web](const QUrl& url) {

                // 停止时会清除缓存 [8/11/2016 Chao.Dong]
                web->stop();
                web->deleteLater();

                emit signalOpenWindow(url);
            });
            return web;
        }
        return QWebView::createWindow(type);
    }

signals:
    // 打开新链接 [8/15/2016 Chao.Dong]
    void linkClicked(const QUrl& url);
    // 打开新窗口信号 [8/9/2016 Chao.Dong]
    void signalOpenWindow(const QUrl& url);
};

 该类的作用是显示web窗口,并根据弹出新窗口的URL地址进行拦截。

结尾

最后的显示效果图:

最后完成的Demo:InterceptOpenWindow.zip

推荐阅读