用QTextBrowser实现的Web浏览器
2016-04-19 23:04
525 查看
qt5.6上的webEngine暂时无法用gcc编译,也没法用在android上,用了很多办法都没法用jni来调用android java的webview,无奈之下用QTextBrowser实现一个最简单的仅支持HTML4子集的Web浏览器,QTextBrowser是没有网络读取功能的,我添加一个网络下载函数,用QtConcurrent异步加载,再用正则表达式解析img标签,然后signal把QTextDocument呈现出来。
这是原型代码,写得比较草率,有兴趣的可以扩展一下QTextBrowser/QTextDocument的源代码得到更多的HTML/CSS渲染效果
这是原型代码,写得比较草率,有兴趣的可以扩展一下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_OBJECT private: 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); else imgFile += 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; else mResources.insert(key, bytes); }
相关文章推荐
- java-WEB中的监听器Lisener
- Android Manifest 用法
- Android学习笔记(二九):嵌入浏览器
- GUI - Web前端开发框架
- Extjs4.0 最新最全视频教程
- MyEclipse Web Project转Eclipse Dynamic Web Project
- axis备忘
- QT学习 第一章:基本对话框
- 使用Shiboken为C++和Qt库创建Python绑定
- Qt 5.6更新至RC版,最终版本近在咫尺
- Erlang实现的一个Web服务器代码实例
- 防止网页脚本病毒执行的方法-from web
- 自学成才的秘密:115个 web Develop 资源
- 使用批处理修改web打印设置笔记 适用于IE
- Apache Web让JSP“动”起来
- web下载的ActiveX控件自动更新
- 推荐六款WEB上传组件性能测试与比较第1/10页
- 关于三种主流WEB架构的思考
- 使用 Iisext.vbs 列出 Web 服务扩展文件的方法
- 使用 Iisext.vbs 删除 Web 服务扩展文件的方法