• 5936阅读
  • 2回复

用QTextBrowser实现的Web浏览器 [复制链接]

上一主题 下一主题
离线hikarisama
 

只看楼主 倒序阅读 楼主  发表于: 2016-04-19
— 本帖被 XChinux 执行加亮操作(2016-04-20) —
qt5.6上的webEngine暂时无法用gcc编译,也没法用在android上,用了很多办法都没法用jni来调用android java的webview,无奈之下用QTextBrowser实现一个最简单的仅支持HTML4子集的Web浏览器,QTextBrowser是没有网络读取功能的,我添加一个网络下载函数,用QtConcurrent异步加载,再用正则表达式解析img标签,然后signal把QTextDocument呈现出来。

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


  1. #ifndef QHTMLBROWSER_H
  2. #define QHTMLBROWSER_H
  3. //** for more information, please refer to http://www.one-lab.net
  4. #include <QtConcurrent>
  5. #include <QtNetwork/QtNetwork>
  6. #include <QTextBrowser>
  7. #include <QTextDocument>
  8. #include <QMap>
  9. #include <QRegExp>
  10. #include <QCryptographicHash>
  11. #include <QApplication>
  12. class QHtmlBrowser : public QObject
  13. {
  14.     Q_OBJECT
  15.     
  16. private:
  17.     QTextBrowser* mBrowser;
  18.     QString mUrl;
  19.     QMap<QString, QByteArray> mResources;
  20. signals:
  21.     void loadFinished();
  22. public slots:
  23.     void onLoadFinished();
  24.     void onRequestUrl(const QUrl& url);
  25. public:
  26.     ~QHtmlBrowser();
  27.     explicit QHtmlBrowser(QTextBrowser* browser);
  28.     void load(const QString& url);
  29.     void addResource(const QString& key, const QByteArray& bytes);
  30. };
  31. #endif // QHTMLBROWSER_H

  1. #include "qhtmlbrowser.h"
  2. //** for more information, please refer to http://www.one-lab.net
  3. #define hit_ext(p) \
  4.     else if (src.endsWith(#p, Qt::CaseInsensitive)) \
  5.         ext = #p
  6. #define index_tag   "index"
  7. #define images_tag   "images://"
  8. QString setUrl(QUrl& parentUrl, const QString& path)
  9. {
  10.     QString srcUrl;
  11.     QString hostPath = parentUrl.host();
  12.     if (parentUrl.port() != 80)
  13.         hostPath += ":" + QString::number(parentUrl.port());
  14.     hostPath += parentUrl.path();
  15.     int pos = hostPath.lastIndexOf('/');
  16.     if (pos > -1)
  17.         hostPath = hostPath.left(pos);
  18.     srcUrl = hostPath + "/" + path;
  19.     while (srcUrl.contains("//"))
  20.         srcUrl.replace("//", "/");
  21.     srcUrl = "http://" + srcUrl;
  22.     return srcUrl;
  23. }
  24. void downloadHtml(QHtmlBrowser* browser, const QString& urlPath, int timeoutSeconds)
  25. {
  26.     QNetworkAccessManager network;
  27.     QNetworkRequest request;
  28.     QUrl url(urlPath);
  29.     request.setUrl(url);
  30.     QByteArray requestContent = urlPath.toUtf8();
  31.     request.setHeader(QNetworkRequest::ContentLengthHeader, requestContent.length());
  32.     bool timeout = false;
  33.     if (QNetworkReply* reply = network.get(request))
  34.     {
  35.         QDateTime stamp = QDateTime::currentDateTime();
  36.         while (reply->isRunning())
  37.         {
  38.             QApplication::processEvents();
  39.             if (stamp.secsTo(QDateTime::currentDateTime()) > timeoutSeconds)
  40.             {
  41.                 reply->abort();
  42.                 timeout = true;
  43.                 break;
  44.             }
  45.         }
  46.         if (!timeout)
  47.         {
  48.             QString content = QString::fromUtf8(reply->readAll());
  49.             QRegExp imgTagRegex("\\<img[^\\>]*src\\s*=\\s*\"([^\"]*)\"[^\\>]*\\>", Qt::CaseInsensitive);
  50.             imgTagRegex.setMinimal(true);
  51.             QStringList imgSrcList;
  52.             QStringList imgTagList;
  53.             int offset = 0;
  54.             while( (offset = imgTagRegex.indexIn(content, offset)) != -1){
  55.                 offset += imgTagRegex.matchedLength();
  56.                 imgTagList.append(imgTagRegex.cap(0));
  57.                 imgSrcList.append(imgTagRegex.cap(1));
  58.             }
  59.             QString srcUrl;
  60.             QString resourcePrefix(images_tag);
  61.             QString ext;
  62.             int index = -1;
  63.             foreach(QString src, imgSrcList)
  64.             {
  65.                 index++;
  66.                 srcUrl.clear();
  67.                 if (src.startsWith("http://", Qt::CaseInsensitive))
  68.                     srcUrl = src;
  69.                 else
  70.                 {
  71.                     if (0){}
  72.                     hit_ext(.png);
  73.                     hit_ext(.jpeg);
  74.                     hit_ext(.jpg);
  75.                     hit_ext(.gif);
  76.                     else continue;
  77.                     if (src.startsWith("://") || src.startsWith("file://", Qt::CaseInsensitive)) continue;
  78.                     srcUrl = setUrl(url, src);
  79.                     request.setUrl(srcUrl);
  80.                     requestContent = srcUrl.toUtf8();
  81.                     request.setHeader(QNetworkRequest::ContentLengthHeader, requestContent.length());
  82.                     QCryptographicHash hash(QCryptographicHash::Md5);
  83.                     if (QNetworkReply* itemReply = network.get(request))
  84.                     {
  85.                         timeout = false;
  86.                         stamp = QDateTime::currentDateTime();
  87.                         while (itemReply->isRunning())
  88.                         {
  89.                             QApplication::processEvents();
  90.                             if (stamp.secsTo(QDateTime::currentDateTime()) > timeoutSeconds)
  91.                             {
  92.                                 itemReply->abort();
  93.                                 timeout = true;
  94.                                 break;
  95.                             }
  96.                         }
  97.                         if (timeout)
  98.                         {
  99.                             delete itemReply;
  100.                             continue;
  101.                         }
  102.                         QString imgFile = resourcePrefix + "/";
  103.                         hash.addData(srcUrl.toUtf8());
  104.                         foreach(char c, hash.result())
  105.                         {
  106.                             int cInt = (int)c;
  107.                             if (cInt < 10)
  108.                                 imgFile += "0" + QString::number(cInt, 16).left(1);
  109.                             else
  110.                                 imgFile += QString::number(cInt, 16).left(2);
  111.                         }
  112.                         imgFile += ext;
  113.                         QString target = imgTagList[index];
  114.                         target.replace(src, imgFile);
  115.                         browser->addResource(imgFile, itemReply->readAll());
  116.                         content.replace(imgTagList[index], target);
  117.                         delete itemReply;
  118.                     }
  119.                 }
  120.             }
  121.             browser->addResource(index_tag, content.toUtf8());
  122.         }
  123.         delete reply;
  124.         emit browser->loadFinished();
  125.     }
  126. }
  127. void QHtmlBrowser::onLoadFinished()
  128. {
  129.     QTextDocument* document = new QTextDocument(mBrowser);
  130.     if (mResources.contains(index_tag))
  131.     {
  132.         foreach(QString key, mResources.keys())
  133.         {
  134.             if (key.startsWith(images_tag))
  135.                 document->addResource(QTextDocument::ImageResource, key, QVariant(mResources[key]));
  136.         }
  137.         document->setHtml(QString::fromUtf8(mResources[index_tag]));
  138.         mBrowser->setDocument(document);
  139.     }
  140. }
  141. QHtmlBrowser::~QHtmlBrowser()
  142. {
  143. }
  144. QHtmlBrowser::QHtmlBrowser(QTextBrowser* browser) : QObject(browser)
  145. {
  146.     mBrowser = browser;
  147.     mBrowser->setReadOnly(true);
  148.     mBrowser->setContextMenuPolicy(Qt::NoContextMenu);
  149.     mBrowser->setAcceptRichText(true);
  150.     mBrowser->setAutoFormatting(QTextEdit::AutoAll);
  151.     connect(this, SIGNAL(loadFinished()), SLOT(onLoadFinished()));
  152.     connect(mBrowser, SIGNAL(anchorClicked(QUrl)), SLOT(onRequestUrl(QUrl)));
  153. }
  154. void QHtmlBrowser::onRequestUrl(const QUrl& url)
  155. {
  156.     QUrl currentUrl(mUrl);
  157.     QString requestingUrl = setUrl(currentUrl, url.toString());
  158.     load(requestingUrl);
  159. }
  160. void QHtmlBrowser::load(const QString &url)
  161. {
  162.     mUrl = url;
  163.     QtConcurrent::run(downloadHtml, this, url, 30);
  164. }
  165. void QHtmlBrowser::addResource(const QString &key, const QByteArray &bytes)
  166. {
  167.     if (mResources.contains(key))
  168.         mResources[key] = bytes;
  169.     else
  170.         mResources.insert(key, bytes);
  171. }


离线nigoole

只看该作者 1楼 发表于: 2016-04-19
   挺有创意的!
有句话说得好:好好学习,天天向上。加油~~!有上船的朋友联系企鹅393320854
离线新手崛起

只看该作者 2楼 发表于: 2016-10-31
楼主你这个能获取到网页源码吗?
只有想不到,没有做不到的
快速回复
限100 字节
 
上一个 下一个