• 用Qt开发简单的浏览器(二)



    一、功能改进

    经过对QtWebKit的一些学习,对之前的浏览器进行一些改进:

    1.增加分页显示多个网页的功能。每个分页都是一个QWebView控件,实现对多个网页的加载。

    2.加入欢迎主页。学习如何创建Qt资源文件,从本地读取欢迎主页的HTML。

    3.添加了前进Forward和后退Back按钮。

    4.此外还明确了SIGNAL和SLOT的命名,SLOT都以handleXXX开头与SIGNAL区分开。


    二、Qt资源文件

    Qt可以很方便的通过资源文件来管理各种资源,就像在VS中创建资源文件一样。
    项目结构如下:



    在Qt Creator中创建四个资源文件html.qrc,script.qrc,style.qrc,resource.qrc分别对应html,
    script,style和resource文件夹,用来存储网页、JS脚本、CSS样式文件和各种图片音频视频资源。



    以html.qrc为例,添加html文件夹中的welcome.html,那么在程序中我们就可以用路径
    qrc:/html/welcome.html来引用它。这里的欢迎页面引用了之前Chrome天气预报插件的
    代码。

    welcome.html
    <html>
    
    <head>	
    	<meta http-equiv="Content-Type" content="text/html; charset=GB2312"/>
    	<link rel="stylesheet" type="text/css" href="qrc:/style/style.css"/>
    	<script type="text/javascript" src="qrc:/script/jquery-1.7.2.min.js"></script>
    	<script type="text/javascript">
    		function init() {			
    			$("#loadingdiv").html("正在加载城市天气预报...");
    			
    			$.getJSON("http://m.weather.com.cn/data/101010100.html",
    				function(data) {
    					$("#loadingdiv").html("");
    					var weatherinfo = data["weatherinfo"];  
    					var datearray = ["", weatherinfo["date_y"], "第二天", "第三天", "第四天", "第五天", "第六天"];  
    					$("#cityname").html(weatherinfo["city"] + "城市天气预报");  
    					for (i = 1; i <= 6; i++) {  
    						var divid = "#div" + i;              
    						$(divid).append(datearray[i]).append("<br>");  
    						var imgurl = "http://m.weather.com.cn/weather_img/" + weatherinfo["img"+(i*2-1)] + ".gif";                 
    						$(divid).append('<img src="' + imgurl + '"/>').append("<br>");  
    						$(divid).append(weatherinfo["temp" + i]).append("<br>");  
    						$(divid).append(weatherinfo["weather" + i]);                 
    					}
    				}
    			);			
    		}
    	</script>
    </head>
    
    <body onload="init()">
    	<h1>Welcome!!!</h1>
    	
    	<div id="weatherreportdiv">
    		<div id="loadingdiv"></div>
    		<div id="cityname"></div>  
    		<hr></hr>
    		<div id="div1" class="weatherdiv"></div>  
    		<div id="div2" class="weatherdiv"></div>  
    		<div id="div3" class="weatherdiv"></div>  
    		<div id="div4" class="weatherdiv"></div>  
    		<div id="div5" class="weatherdiv"></div>  
    		<div id="div6" class="weatherdiv"></div>  
    	</div>
    
    </body>
    
    </html>

    style.css
    h1 {
    	text-align: center;
    }
    
    #weatherreportdiv {
    	height: 300px;
    	 700px;
    	text-align: center;  
        font-size: 20px;  
        font-weight: bold;  
        margin: 5px;  
    }
    
    #cityname {  
        text-align: center;  
        font-size: 20px;  
        font-weight: bold;  
        margin: 5px;  
    }  
     
    .weatherdiv {  
        float: left;  
         15%;  
        margin: 5px;  
    }
    

    管理资源就是这么简单,下面来看改进后的代码。


    三、源码实现

    在AddressBar中新加一个SLOT函数handleAddressChanged,处理当分页切换时URL的变化。

    addressbar.h
    #ifndef ADDRESSBAR_H
    #define ADDRESSBAR_H
    
    #include <QWidget>
    #include <QLineEdit>
    #include <QPushButton>
    #include <QHBoxLayout>
    #include <QUrl>
    #include <QString>
    
    class AddressBar : public QWidget
    {
        Q_OBJECT
    public:
        explicit AddressBar(QWidget *parent = 0);    
        
    signals:
        void go(const QUrl&);
        void back();
        void forward();
        void newPage();
        
    public slots:
        void handleGoToSite();
        void handleAddressChanged(const QUrl&);
    
    private:
        QLineEdit *addressEdit;
        QPushButton *newButton;
        QPushButton *backButton;
        QPushButton *forwardButton;
        QPushButton *goButton;
        QHBoxLayout *layout;
    };
    
    #endif // ADDRESSBAR_H
    

    addressbar.cpp
    #include "addressbar.h"
    
    AddressBar::AddressBar(QWidget *parent) :
        QWidget(parent)
    {
        // 1.Create widget
        addressEdit = new QLineEdit;
        newButton = new QPushButton("New");
        backButton = new QPushButton("Back");
        forwardButton = new QPushButton("Forward");
        goButton = new QPushButton("Go");
    
        // 2.Set property
    
        // 3.Connect signal and slot
        connect(goButton, SIGNAL(clicked()), this, SLOT(handleGoToSite()));
        connect(addressEdit, SIGNAL(returnPressed()), this, SLOT(handleGoToSite()));
        connect(backButton, SIGNAL(clicked()), this, SIGNAL(back()));
        connect(forwardButton, SIGNAL(clicked()), this, SIGNAL(forward()));
        connect(newButton, SIGNAL(clicked()), this, SIGNAL(newPage()));
    
        // 4.Add to layout
        layout = new QHBoxLayout;
        layout->addWidget(newButton);
        layout->addWidget(backButton);
        layout->addWidget(forwardButton);
        layout->addWidget(addressEdit);
        layout->addWidget(goButton);
        this->setLayout(layout);
    }
    
    void AddressBar::handleGoToSite()
    {
        QString address = addressEdit->text();
        emit go(QUrl(address));
    }
    
    void AddressBar::handleAddressChanged(const QUrl &url)
    {
        addressEdit->setText(url.toString());
    }
    

    新建了TabPage继承了QTabWidget,管理所有分页。

    tabpage.h
    #ifndef TABPAGE_H
    #define TABPAGE_H
    
    #include <QTabWidget>
    #include <QList>
    #include "htmlview.h"
    
    class TabPage : public QTabWidget
    {
        Q_OBJECT
    public:
        explicit TabPage(QWidget *parent = 0);
        ~TabPage();
        
    signals:
        void urlChanged(const QUrl&);
        
    public slots:
        void handleNewTab();
        void handleLoadNewPage(const QUrl&);
        void handleBack();
        void handleForward();
    
    private slots:
        void handleTabChanged(int);
        void handleTabClosed(int);
        void handleLinkClicked(const QUrl&);
    
    private:    
        QList<QWebView*> viewList;
    };
    
    #endif // TABPAGE_H
    

    tabpage.cpp
    #include "tabpage.h"
    #include <QtDebug>
    
    TabPage::TabPage(QWidget *parent) :
        QTabWidget(parent)
    {
        // Set property
        this->setTabsClosable(true);
    
        // Connect built-in signal to customized one to convert index to url
        connect(this, SIGNAL(currentChanged(int)), SLOT(handleTabChanged(int)));
        connect(this, SIGNAL(tabCloseRequested(int)), this, SLOT(handleTabClosed(int)));
    
        // Create new tab for home page
        this->handleNewTab();
    }
    
    TabPage::~TabPage()
    {    
    }
    
    void TabPage::handleNewTab()
    {
        HtmlView *view = new HtmlView;
        view->load(QUrl("qrc:/html/welcome.html"));
        //view->page()->setForwardUnsupportedContent(true);
        view->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);
    
        // Monitor linkClicked signal    
        connect(view, SIGNAL(linkClicked(const QUrl&)), this, SLOT(handleLinkClicked(const QUrl&)));    
    
        // Add and activate this new tab
        int index = this->addTab(view, "Welcome");
        this->setCurrentIndex(index);
    
        viewList.append(view);
    }
    
    void TabPage::handleLoadNewPage(const QUrl &url)
    {
        qDebug() << "loadNewPage: " << url.toString();
        HtmlView *view = (HtmlView*) this->currentWidget();
        view->load(url);
    }
    
    void TabPage::handleBack()
    {
        HtmlView *view = (HtmlView*) this->currentWidget();
        view->back();
        emit urlChanged(view->url());
    }
    
    void TabPage::handleForward()
    {
        HtmlView *view = (HtmlView*) this->currentWidget();
        view->forward();
        emit urlChanged(view->url());
    }
    
    void TabPage::handleTabChanged(int index)
    {
        if (index > viewList.length() - 1)
            return;
    
        // index is the new tab index
        QWebView* view = viewList[index];
        emit urlChanged(view->url());
    }
    
    void TabPage::handleTabClosed(int index)
    {
        if (index > viewList.length() - 1)
            return;
    
        this->removeTab(index);
        QWebView* view = viewList[index];
        viewList.removeAt(index);
    
        delete view;
    }
    
    void TabPage::handleLinkClicked(const QUrl& url)
    {
        qDebug() << "handleLinkClicked: " << url.toString();
        HtmlView *view = (HtmlView*) this->currentWidget();
        view->load(url);
        emit urlChanged(url);
    }
    

    接下来是MainWindow,改动很小。

    mainwindow.h
    #ifndef MAINWINDOW_H
    #define MAINWINDOW_H
    
    #include <QWidget>
    #include <QLineEdit>
    #include <QPushButton>
    #include <QGridLayout>
    #include <QtWebKit>
    #include <QMainWindow>
    #include "addressbar.h"
    #include "htmlview.h"
    #include "tabpage.h"
    
    namespace Ui {
    class MainWindow;
    }
    
    class MainWindow : public QMainWindow
    {
        Q_OBJECT
        
    public:
        explicit MainWindow(QWidget *parent = 0);
        ~MainWindow();
        
    private:
        Ui::MainWindow *ui;    
    };
    
    #endif // MAINWINDOW_H
    

    mainwindow.cpp
    #include "mainwindow.h"
    #include "ui_mainwindow.h"
    
    MainWindow::MainWindow(QWidget *parent) :
        QMainWindow(parent),
        ui(new Ui::MainWindow)
    {
        //ui->setupUi(this);
        // 0.Global setting
        QWebSettings* defaultSettings = QWebSettings::globalSettings();
        // We use JavaScript, so set it to be enabled.
        defaultSettings->setAttribute(QWebSettings::JavascriptEnabled, true);
        // Plug-ins must be set to be enabled to use plug-ins.
        defaultSettings->setAttribute(QWebSettings::PluginsEnabled,true);
        defaultSettings->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls,true);
        defaultSettings->setObjectCacheCapacities(0, 0, 0);
    
        // 1.Create widget
        QWidget *centralWidget = new QWidget(this);
        AddressBar *bar = new AddressBar;    
        TabPage *tab = new TabPage;
    
        // 2.Set property
        this->setCentralWidget(centralWidget);
        this->setWindowTitle("My Browser v1.0");
        this->resize(800, 600);
    
        // 3.Connect widget        
        QObject::connect(bar, SIGNAL(newPage()),tab, SLOT(handleNewTab()));
        QObject::connect(bar, SIGNAL(back()),tab, SLOT(handleBack()));
        QObject::connect(bar, SIGNAL(forward()),tab, SLOT(handleForward()));
        QObject::connect(bar, SIGNAL(go(QUrl)), tab, SLOT(handleLoadNewPage(QUrl)));
        QObject::connect(tab, SIGNAL(urlChanged(QUrl)), bar, SLOT(handleAddressChanged(QUrl)));
    
        // 4.Add widget to layout
        QGridLayout *layout = new QGridLayout;
        layout->addWidget(bar, 0, 0, 1, 10);
        layout->addWidget(tab, 1, 0, 1, 10);
        centralWidget->setLayout(layout);
    }
    
    MainWindow::~MainWindow()
    {
        //delete ui;
    }
    


    四、关键问题

    1.需要为QWebView中的QWebPage设置才能使页面内链接可以正常跳转。

         view->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);

    2.需要为AJAX调用设置:

        QWebSettings* defaultSettings = QWebSettings::globalSettings();
        // We use JavaScript, so set it to be enabled.
        defaultSettings->setAttribute(QWebSettings::JavascriptEnabled, true);
        // Plug-ins must be set to be enabled to use plug-ins.
        defaultSettings->setAttribute(QWebSettings::PluginsEnabled,true);
        defaultSettings->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls,true);
        defaultSettings->setObjectCacheCapacities(0, 0, 0);


    五、最终效果

    1.程序开始运行,进入欢迎页面。



    2.多页面浏览




    2012年7月4日 补充

    htmlview.h

    #ifndef HTMLVIEW_H
    #define HTMLVIEW_H
    
    #include <QWebView>
    
    class HtmlView : public QWebView
    {
        Q_OBJECT
    public:
        explicit HtmlView(QWidget *parent = 0);
        
    signals:
        
    public slots:
        void loadNewPage(const QUrl &url);
        
    };
    
    #endif // HTMLVIEW_H
    htmlview.cpp

    #include "htmlview.h"
    
    HtmlView::HtmlView(QWidget *parent) :
        QWebView(parent)
    {
    }
    
    void HtmlView::loadNewPage(const QUrl &url)
    {    
        this->load(url);
    }

    2014年8月13日

    感觉真的很神奇,本来主攻是Java,没想到业余时间写的一个Qt小项目竟成了我访问最高的文章,真是无心插柳柳成荫,谢谢大家的捧场!


    2015年8月16日

    需要源码的同学还真不少啊,现在源码已经共享到GitHub上了,请自行获取吧!地址是:https://github.com/cdai/qtbrowser







  • 相关阅读:
    磁盘挂载与卸载
    Linux iostat监测IO状态
    Chrome 清除某个特定网站下的缓存
    15个极好的Linux find命令示例
    jenkins构建执行shell 所有命令出现command not found
    SharePoint 更新文档库文档标题(Title)字段
    SharePoint 服务器端对象模型操作文档库(上传/授权/查看权限)
    SharePoint 服务器端对象模型操作用户组(创建/添加/删除)
    SharePoint 2013 版本功能对比
    SharePoint 如何找到List的Template ID
  • 原文地址:https://www.cnblogs.com/xiaomaohai/p/6157836.html
Copyright © 2020-2023  润新知