qt5.6上的webEngine暂时无法用gcc编译,也没法用在android上,用了很多办法都没法用jni来调用android java的webview,无奈之下用QTextBrowser实现一个最简单的仅支持HTML4子集的Web浏览器,QTextBrowser是没有网络读取功能的,我添加一个网络下载函数,用QtConcurrent异步加载,再用正则表达式解析img标签,然后signal把QTextDocument呈现出来。

这是原型代码,写得比较草率,有兴趣的可以扩展一下QTextBrowser/QTextDocument的源代码得到更多的HTML/CSS渲染效果

#ifndef QHTMLBROWSER_H
#define QHTMLBROWSER_H//** for more information, please refer to http://www.one-lab.net#include <QtConcurrent>
#include <QtNetwork/QtNetwork>
#include <QTextBrowser>
#include <QTextDocument>
#include <QMap>
#include <QRegExp>
#include <QCryptographicHash>
#include <QApplication>class QHtmlBrowser : public QObject
{Q_OBJECTprivate:QTextBrowser* mBrowser;QString mUrl;QMap<QString, QByteArray> mResources;signals:void loadFinished();public slots:void onLoadFinished();void onRequestUrl(const QUrl& url);public:~QHtmlBrowser();explicit QHtmlBrowser(QTextBrowser* browser);void load(const QString& url);void addResource(const QString& key, const QByteArray& bytes);
};#endif // QHTMLBROWSER_H
#include "qhtmlbrowser.h"
//** for more information, please refer to http://www.one-lab.net#define hit_ext(p) \else if (src.endsWith(#p, Qt::CaseInsensitive)) \ext = #p
#define index_tag   "index"
#define images_tag   "images://"QString setUrl(QUrl& parentUrl, const QString& path)
{QString srcUrl;QString hostPath = parentUrl.host();if (parentUrl.port() != 80)hostPath += ":" + QString::number(parentUrl.port());hostPath += parentUrl.path();int pos = hostPath.lastIndexOf('/');if (pos > -1)hostPath = hostPath.left(pos);srcUrl = hostPath + "/" + path;while (srcUrl.contains("//"))srcUrl.replace("//", "/");srcUrl = "http://" + srcUrl;return srcUrl;
}void downloadHtml(QHtmlBrowser* browser, const QString& urlPath, int timeoutSeconds)
{QNetworkAccessManager network;QNetworkRequest request;QUrl url(urlPath);request.setUrl(url);QByteArray requestContent = urlPath.toUtf8();request.setHeader(QNetworkRequest::ContentLengthHeader, requestContent.length());bool timeout = false;if (QNetworkReply* reply = network.get(request)){QDateTime stamp = QDateTime::currentDateTime();while (reply->isRunning()){QApplication::processEvents();if (stamp.secsTo(QDateTime::currentDateTime()) > timeoutSeconds){reply->abort();timeout = true;break;}}if (!timeout){QString content = QString::fromUtf8(reply->readAll());QRegExp imgTagRegex("\\<img[^\\>]*src\\s*=\\s*\"([^\"]*)\"[^\\>]*\\>", Qt::CaseInsensitive);imgTagRegex.setMinimal(true);QStringList imgSrcList;QStringList imgTagList;int offset = 0;while( (offset = imgTagRegex.indexIn(content, offset)) != -1){offset += imgTagRegex.matchedLength();imgTagList.append(imgTagRegex.cap(0));imgSrcList.append(imgTagRegex.cap(1));}QString srcUrl;QString resourcePrefix(images_tag);QString ext;int index = -1;foreach(QString src, imgSrcList){index++;srcUrl.clear();if (src.startsWith("http://", Qt::CaseInsensitive))srcUrl = src;else{if (0){}hit_ext(.png);hit_ext(.jpeg);hit_ext(.jpg);hit_ext(.gif);else continue;if (src.startsWith("://") || src.startsWith("file://", Qt::CaseInsensitive)) continue;srcUrl = setUrl(url, src);request.setUrl(srcUrl);requestContent = srcUrl.toUtf8();request.setHeader(QNetworkRequest::ContentLengthHeader, requestContent.length());QCryptographicHash hash(QCryptographicHash::Md5);if (QNetworkReply* itemReply = network.get(request)){timeout = false;stamp = QDateTime::currentDateTime();while (itemReply->isRunning()){QApplication::processEvents();if (stamp.secsTo(QDateTime::currentDateTime()) > timeoutSeconds){itemReply->abort();timeout = true;break;}}if (timeout){delete itemReply;continue;}QString imgFile = resourcePrefix + "/";hash.addData(srcUrl.toUtf8());foreach(char c, hash.result()){int cInt = (int)c;if (cInt < 10)imgFile += "0" + QString::number(cInt, 16).left(1);elseimgFile += QString::number(cInt, 16).left(2);}imgFile += ext;QString target = imgTagList[index];target.replace(src, imgFile);browser->addResource(imgFile, itemReply->readAll());content.replace(imgTagList[index], target);delete itemReply;}}}browser->addResource(index_tag, content.toUtf8());}delete reply;emit browser->loadFinished();}
}void QHtmlBrowser::onLoadFinished()
{QTextDocument* document = new QTextDocument(mBrowser);if (mResources.contains(index_tag)){foreach(QString key, mResources.keys()){if (key.startsWith(images_tag))document->addResource(QTextDocument::ImageResource, key, QVariant(mResources[key]));}document->setHtml(QString::fromUtf8(mResources[index_tag]));mBrowser->setDocument(document);}
}QHtmlBrowser::~QHtmlBrowser()
{
}QHtmlBrowser::QHtmlBrowser(QTextBrowser* browser) : QObject(browser)
{mBrowser = browser;mBrowser->setReadOnly(true);mBrowser->setContextMenuPolicy(Qt::NoContextMenu);mBrowser->setAcceptRichText(true);mBrowser->setAutoFormatting(QTextEdit::AutoAll);connect(this, SIGNAL(loadFinished()), SLOT(onLoadFinished()));connect(mBrowser, SIGNAL(anchorClicked(QUrl)), SLOT(onRequestUrl(QUrl)));
}void QHtmlBrowser::onRequestUrl(const QUrl& url)
{QUrl currentUrl(mUrl);QString requestingUrl = setUrl(currentUrl, url.toString());load(requestingUrl);
}void QHtmlBrowser::load(const QString &url)
{mUrl = url;QtConcurrent::run(downloadHtml, this, url, 30);
}void QHtmlBrowser::addResource(const QString &key, const QByteArray &bytes)
{if (mResources.contains(key))mResources[key] = bytes;elsemResources.insert(key, bytes);
}

用QTextBrowser实现的Web浏览器相关推荐

  1. [C# 网络编程系列]专题四:自定义Web浏览器

    前言: 前一个专题介绍了自定义的Web服务器,然而向Web服务器发出请求的正是本专题要介绍的Web浏览器,本专题通过简单自定义一个Web浏览器来简单介绍浏览器的工作原理,以及帮助一些初学者揭开浏览器这 ...

  2. Beaker:一个基于Electron的点对点Web浏览器

    Beaker是一个基于Electron.Chromium和Node.js的实验性.点对点Web浏览器.Beaker包含新的基于Dat的API,用于构建无主机应用程序,同时又保持与传统Web的兼容性. ...

  3. 大多数Web浏览器中都可以使用PUT,DELETE,HEAD等方法吗?

    我在这里看到了几个问题,例如如何调试RESTful服务 ,其中提到: 不幸的是,同一浏览器不允许我测试HTTP PUT,DELETE,并且在某种程度上甚至无法测试HTTP POST. 我还听说其他一些 ...

  4. 第十一章:WEB浏览器中的javascript

    客户端javascript涵盖在本系列的第二部分第10章,主要讲解javascript是如何在web浏览器中实现的,这些章节介绍了大量的脚本宿主对象,这些对象可以表示浏览器窗口.文档树的内容.这些章节 ...

  5. 禁用Cookie在web浏览器中读取/写入c#应用程序

    我希望网站无法读取cookie或在webbrowser c#控制应用程序中写入新的cookie.当webbrowser c#应用程序运行时,我宁愿禁用所有网站的所有读/写cookie操作,如果不是,那 ...

  6. 服务器应用程序不可用您试图在此 Web 服务器上访问的 Web 应用程序当前不可用。请点击 Web 浏览器中的“刷...

    错误提示: 服务器应用程序不可用您试图在此 Web 服务器上访问的 Web 应用程序当前不可用.请点击 Web 浏览器中的"刷新"按钮重试您的请求. 管理员注意事项:详述此特定请求 ...

  7. [ZT]介绍 10 款非主流的 Web 浏览器

    尽管大多数的互联网用户都在使用包括 IE.火狐和 Chrome 等主流浏览器,但互联网就是这么百花齐放,一些在某方面有特长的浏览器可能会受某些用户青睐,例如经常访问社交网络的会需要社交版浏览器之类的. ...

  8. python 浏览器,轻量级Python Web浏览器

    这里有一个奇怪的要求,但是我真的不知道答案.在 我正在编写一个python应用程序,它显示web页面和本地存储的图像.在 我需要的是一种使用python显示web页面的方法,这种方法非常轻量级而且非常 ...

  9. 如何在Windows上使用64位Web浏览器

    Google and Mozilla now offer 64-bit versions of Chrome and Firefox for Windows. Here's how to find o ...

最新文章

  1. Python:Bug 官网不要了,全迁去 GitHub
  2. Javascript调试技巧整理
  3. 百度世界-“框天地”
  4. 使用FlowDroid生成Android应用程序的函数调用图
  5. CString + UINT Error:有多个运算符+=与这些操作数匹配
  6. eclipse中的感叹号和x号解决方法
  7. k8s 查看ip地址属于哪个pod_Kubernetes Pod 如何获取 IP 地址
  8. dp主机_HDMI和DP谁才是未来主流?
  9. 先富带动后富:雷军带领一大批程序员发家致富
  10. VB:将短文件名格式转成长文件名
  11. js 报错:object is not a function
  12. 开盘前1.5秒下单可追涨停股
  13. STM32的ADC多通道采集的实现
  14. hdu 5956 The Elder
  15. 做LED照明类产品有感
  16. UVM-入门实验2_uvm代码实现
  17. 普罗米修斯(Prometheus)安装配置部署
  18. 决胜b端产品经理学习笔记01(持续更新版)
  19. 【CC2530授课笔记】⑧ PWM实现呼吸灯,RGB三色灯,蜂鸣器播放音乐
  20. Joplin利用TeraCLOUD进行WebDAV同步完美替代坚果云同步

热门文章

  1. 2022年金属非金属矿山(地下矿山)安全管理人员考试题及模拟考试
  2. 出售二手房如何发布信息
  3. Linphone-android 登录过程增加自定义消息头流程分析
  4. 实现不同分辨率电脑页面自适应
  5. FS61C27封装2.7V低电压监测器IC
  6. 专业高效的社群助手哪家好用?
  7. 微信支付(小程序)-java配置
  8. 小程序绘制表格table(表头固定,可上下左右滑动)
  9. linux绝对路径写法,javalinux获取文件路径怎么写
  10. 解析Quorum -- 摩根大通的企业级区块链解决方案