Qt中web控件使用的解决办法

1. 问题描述

Qt项目打包交付后在一台客户机上面出现了打开界面就停止运行
Qt中web控件使用的解决办法_第1张图片

由于在客户机上没有代码调试环境,不能联网,不能重装系统,就直接用该客户机器上的vs2010对exe界面程序进行调试

发现中断进程中提示“下面的框架可能不正确或缺失,没有为ntdll.dll加载符号”,再看下面的进程,有对Qt5WebEngineWidgets.dll,Qt5WebEngineCore.dll,Qt5WebChannel.dll的提示,这三个动态库是项目使用了QWebEngineView控件才加进去的,是通过间接调用QtWebEngineProcess.exe来进行,然后,在打包的软件的路径下双击QtWebEngineProcess.exe发现也是会停止运行,在别的客户机上双击这个exe是一闪而过,也就是该机器系统不支持这个库,当前qt版本是5.14.2,后来又测试了以下方法都没有在该2机器上解决这个问题:

  1. 用qt msvc2017_32编译软件,在该机器上同样的问题
  2. 替换Qt版本为5.14.0,在该机器上同样的问题
  3. 替换其他同型号客户机上可用的ntdll.dll等系统库(不要轻易尝试,可能会让系统奔溃),该机器上测试失败
  4. Qt bug列表网发现说是可能是机器显卡和显卡驱动不匹配导致,然后重装该机器显卡驱动(联想机器,在官网下载的专用显卡驱动,没有测试其他通用显卡驱动),还是没有解决

2. 问题定位

由于该客户机对解决问题的局限比较大,经过各种方法测试,后在工程中去掉QWebEngineView控件的使用,重新编译发现在该机器可以正常运行,但是少了用到QWebEngineView的部分功能
将问题定位为QWebEngineView(QtWebEngineProcess.exe)控件对部分旧机器或系统兼容性不好

3. 问题解决方案(选用Qt别的web控件)

在不同QT版本中使用的类和方法不同:

  1. Qt4中使用webkit模块;

  2. Qt5 ~Qt5.5使用webkitwidgets模块;

  3. Qt5.6以上MSVC版本使用webenginewidgets模块,Qt5.6以后,移除了QtWebkit这个组件

  4. Qt5.6以后的mingw版本,不能使用QtWebEngine,只能使用QAxWidget控件

项目当前使用的是第三种方式出现问题,排除第三种方式,第一种是Qt4也排除掉,可选第二种或者第四种,这里选择用QAxWidget的方案,不用降低Qt版本。

先引用下几种方式的使用方法:

1)Qt4版本
   Qt4使用webkit模块。

   1. 创建一个Widget类的QT工程,在pro工程文件中添加 webkit network :
    QT       += core gui webkit network
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
     
    TARGET = web
    TEMPLATE = app
     
     
    SOURCES += main.cpp\
               widget.cpp
     
    HEADERS  += widget.h
     
    FORMS    += widget.ui
    2. 编辑widget.h文件,在Widget类中添加一个指针成员,该指针指向一个QWebView类:
    #ifndef WIDGET_H
    #define WIDGET_H
     
    #include 
    #include 
     
     
    namespace Ui {
     
    class Widget;
    }
     
    class Widget : public QWidget
    {
     
        Q_OBJECT
     
    public:
        explicit Widget(QWidget *parent = 0);
        ~Widget();
     
        QWebView    *view;
     
     
    private:
        Ui::Widget *ui;
    };
     
    #endif // WIDGET_H
 3. 修改widget.cpp,实现下面两个成员函数
    #include "widget.h"
    #include "ui_widget.h"
     
    Widget::Widget(QWidget *parent) :
        Widget(parent),
        ui(new Ui::Widget)
    {
     
        ui->setupUi(this);
     
        view = new QWebView(this);
        view->load(QUrl("http://www.baidu.com"));
        view.showMaximized();
    }
     
    Widget::~Widget()
    {
     
        delete view;
        delete ui;
    }
2) Qt5 ~ Qt5.5版本
 Qt5版本之后,将QWebView、QWebFrame、QWebPage、QWebInspector等类被单独移到了webkitwidgets模块,不再在QtWebKit模块中,因此需使用webkitwidgets模块。

 和Qt4的区别仅在于pro文件中添加的模块不同和widget.h文件中包含的头文件不同。
    QT       += core gui webkitwidgets network
    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
    #ifndef WIDGET_H
    #define WIDGET_H
     
    #include 
    #include 
3) Qt5.6及以上版本
 Qt5.5.1是最后一个支持webkitwidgets的版本,在5.6版本以及之后的版本,Qt将webkitwidgets模块移除,并用一个新的模块webenginewidgets代替。
 1. 创建一个Widget类的QT工程,在pro工程文件中添加 webenginewidgets:
 QT       += core gui webenginewidgets
  
 greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
  
 TARGET = web
 TEMPLATE = app
  
  
 SOURCES += \
         main.cpp \
         widget.cpp
  
 HEADERS += \
         widget.h
  
 FORMS += \
         widget.ui
  
 RESOURCES +=
 2. 编辑widget.h文件,包含QWebEngineView头文件,并在Widget类中添加一个指针成员,该指针指向一个QWebEngineView类:
    #ifndef WIDGET_H
    #define WIDGET_H
     
    #include 
    #include 
     
     
    namespace Ui {
     
    class Widget;
    }
     
    class Widget : public QWidget
    {
     
        Q_OBJECT
     
    public:
        explicit Widget(QWidget *parent = 0);
        ~Widget();
     
        QWebEngineView    *view;
     
     
    private:
        Ui::Widget *ui;
    };
     
    #endif // WIDGET_H
3. 修改widget.cpp,实现下面两个成员函数
    #include "widget.h"
    #include "ui_widget.h"
     
    Widget::Widget(QWidget *parent) :
        Widget(parent),
        ui(new Ui::Widget)
    {
     
        ui->setupUi(this);
     
        view = new QWebEngineView(this);
        view->load(QUrl(QStringLiteral("http://www.baidu.com")));
        view.showMaximized();
    }
     
    Widget::~Widget()
    {
     
        delete view;
        delete ui;
    }
4)Qt5.6以后的mingw版本,使用 QAxWidget 显示网页

使用QAxWidget前需要注意两点:
1.QAxContainer.lib,QAxServer.lib库不可缺。
2.开发机本身具有相应的IE游览器(注册表文件一致)

第①种 QAxContainer.lib,QAxServer.lib引用方式:

Qt中web控件使用的解决办法_第2张图片

关于注册表文件:
Qt中web控件使用的解决办法_第3张图片

QAxWidget *flash = new QAxWidget(0, 0);      //QAxWidget使用的是ActiveX插件
flash->resize(600, 400);                    //设置该控件的初始大小
flash->setControl(QString::fromUtf8("{8856F961-340A-11D0-A96B-00C04FD705A2}"));//注册组件ID
flash->setProperty("DisplayAlerts", false);//不显示警告信息
flash->setProperty("DisplayScrollBars", true);//不显示滚动条
QString webstr = QString("www.baidu.com");//设置要打开的网页
flash->dynamicCall("Navigate(const QString&)", webstr);//显示网页
flash->show();
第②种 在pro文件里加入一句:
QT += axcontainer

显示网页的代码如下:

this->ui->axWidget->setControl(QString::fromUtf8("{8856F961-340A-11D0-A96B-00C04FD705A2}"));//注册组件ID
this->ui->axWidget->setProperty("DisplayAlerts",false);//不显示警告信息
this->ui->axWidget->setProperty("DisplayScrollBars",true);//不显示滚动条
QString webstr=QString("github.com");//设置要打开的网页
this->ui->axWidget->dynamicCall("Navigate(const QString&)",webstr);//显示网页

webWidget->dynamicCall("Navigate(const QString&)", "file:///"+QCoreApplication::applicationDirPath()+"/drawChart/report.html");	//加载本地文件
5)使用 QAxWidget 的注意点

这样显示普通的JavaScript脚本是没啥问题的,但是当引用jQuery等js的封装库的时候会无法解析,提示如下:
Qt中web控件使用的解决办法_第4张图片Qt中web控件使用的解决办法_第5张图片
原因是该控件默认使用的版本是IE7的兼容模式,对jq不怎么支持,需要指定控件加载的IE内核版本来解决这个问题,有修改注册表,HTML中强制指定等方法,详细可参考:
WebBrowser控件默认使用IE9,IE10的方法

我的用途是加载本地HTML文件,所以选用里面最简便的方法是在.html文件添加下面的指定:

在html头 加标签 强制使用最新的ie渲染
 <meta http-equiv="X-UA-Compatible" content="IE=edge">
或者强制使用最新的ie11渲染
<meta http-equiv="X-UA-Compatible" content="IE=EmulateIE11"/>

然后可以正常显示本地HTML页面了。

更多QAxWidget 资料

参考:

链接1
链接2
链接3

你可能感兴趣的:(Qt问题解决)