qt版本的浏览器开发

http://blog.csdn.net/dc_726/article/details/7584205



1.代码实现

工程目录结构如下:



AddressBar类包含了地址栏和按钮两个控件,将地址栏回车和按钮点击信号与goToSite()槽连接。
当回车和点击事件发生时,goToSite()将获得Url地址并发送go(QUrl)信号。

addressbar.h
[cpp]  view plain copy
  1. #ifndef ADDRESSBAR_H  
  2. #define ADDRESSBAR_H  
  3.   
  4. #include <QWidget>  
  5. #include <QLineEdit>  
  6. #include <QPushButton>  
  7. #include <QHBoxLayout>  
  8. #include <QUrl>  
  9. #include <QString>  
  10.   
  11. class AddressBar : public QWidget  
  12. {  
  13.     Q_OBJECT  
  14. public:  
  15.     explicit AddressBar(QWidget *parent = 0);      
  16.       
  17. signals:  
  18.     void go(QUrl);  
  19.       
  20. public slots:  
  21.     void goToSite();  
  22.   
  23. private:  
  24.     QLineEdit *addressEdit;  
  25.     QPushButton *goButton;  
  26.     QHBoxLayout *layout;  
  27. };  
  28.   
  29. #endif // ADDRESSBAR_H  

addressbar.cpp
[cpp]  view plain copy
  1. #include "addressbar.h"  
  2.   
  3. AddressBar::AddressBar(QWidget *parent) :  
  4.     QWidget(parent)  
  5. {  
  6.     addressEdit = new QLineEdit(parent);  
  7.     goButton = new QPushButton("Go", parent);  
  8.   
  9.     layout = new QHBoxLayout;  
  10.     layout->addWidget(addressEdit);  
  11.     layout->addWidget(goButton);  
  12.     this->setLayout(layout);  
  13.   
  14.     connect(goButton, SIGNAL(clicked()), this, SLOT(goToSite()));  
  15.     connect(addressEdit, SIGNAL(returnPressed()), this, SLOT(goToSite()));  
  16. }  
  17.   
  18. void AddressBar::goToSite()  
  19. {  
  20.     QString address = addressEdit->text();  
  21.     emit go(QUrl(address));  
  22. }  

接下来是QtWebkit包中的主要类QWebView,我们借助这个类来渲染Url指向的网页。
为了当用户在地址栏回车或者点击Go按钮时能够自动加载网页,我们需要给QWebView
添加loadNewPage(QUrl)槽(因为QWebView没有类似load(QUrl)的槽),并将其与go(QUrl)
信号连接。所以我们实现一个QWebView的子类HtmlView。

htmlview.h
[cpp]  view plain copy
  1. #ifndef HTMLVIEW_H  
  2. #define HTMLVIEW_H  
  3.   
  4. #include <QWebView>  
  5.   
  6. class HtmlView : public QWebView  
  7. {  
  8.     Q_OBJECT  
  9. public:  
  10.     explicit HtmlView(QWidget *parent = 0);  
  11.       
  12. signals:  
  13.       
  14. public slots:  
  15.     void loadNewPage(const QUrl &url);  
  16.       
  17. };  
  18.   
  19. #endif // HTMLVIEW_H  

htmlview.cpp
[cpp]  view plain copy
  1. #include "htmlview.h"  
  2.   
  3. HtmlView::HtmlView(QWidget *parent) :  
  4.     QWebView(parent)  
  5. {  
  6. }  
  7.   
  8. void HtmlView::loadNewPage(const QUrl &url)  
  9. {  
  10.     this->load(url);  
  11. }  

接下来实现程序的主窗口QMainWindow,将AddressBar和HtmlView放置其中。

mainwindow.h
[cpp]  view plain copy
  1. #ifndef MAINWINDOW_H  
  2. #define MAINWINDOW_H  
  3.   
  4. #include <QWidget>  
  5. #include <QLineEdit>  
  6. #include <QPushButton>  
  7. #include <QGridLayout>  
  8. #include <QtWebKit>  
  9. #include <QMainWindow>  
  10. #include "addressbar.h"  
  11. #include "htmlview.h"  
  12.   
  13. class MainWindow : public QMainWindow  
  14. {  
  15.     Q_OBJECT  
  16.       
  17. public:  
  18.     explicit MainWindow(QWidget *parent = 0);  
  19.   
  20. };  
  21.   
  22. #endif // MAINWINDOW_H  

mainwindow.cpp
[cpp]  view plain copy
  1. #include "mainwindow.h"  
  2. #include "ui_mainwindow.h"  
  3.   
  4. MainWindow::MainWindow(QWidget *parent) :  
  5.     QMainWindow(parent)  
  6. {  
  7.     // 1.Create widget  
  8.     QWidget *centralWidget = new QWidget(this);  
  9.     AddressBar *bar = new AddressBar;  
  10.     HtmlView *view = new HtmlView;  
  11.   
  12.     // 2.Add widget to layout  
  13.     QGridLayout *layout = new QGridLayout;  
  14.     layout->addWidget(bar, 0, 0, 1, 10);  
  15.     layout->addWidget(view, 1, 0, 1, 10);  
  16.     centralWidget->setLayout(layout);  
  17.   
  18.     // 3.Connect widget  
  19.     QObject::connect(bar, SIGNAL(go(QUrl)), view, SLOT(loadNewPage(QUrl)));  
  20.   
  21.     this->setCentralWidget(centralWidget);  
  22.     this->setWindowTitle("My Browser v1.0");  
  23.     this->resize(640, 480);  
  24. }  

最后是程序的入口main.cpp
[cpp]  view plain copy
  1. #include <QApplication>  
  2. #include "mainwindow.h"  
  3.   
  4. int main(int argc, char *argv[])  
  5. {  
  6.     QApplication app(argc, argv);  
  7.   
  8.     MainWindow *window = new MainWindow;  
  9.     window->show();  
  10.       
  11.     return app.exec();  
  12. }  


2.事件流分析



我们分别为AddressBar和HtmlView自定义了两个槽goToSite(QUrl)和loadNewPage(QUrl),以及新的信号go(QUrl)。
就是为了将Url地址传递给QWebView的load函数。

这里需要注意的是SIGNAL-SLOT机制是Qt的内部机制,它是同步执行的。源头上returnPressed()和clicked()槽的触发,
是从操作系统的事件队列中得到的,并进行异步的处理。以QPushButton的clicked()槽的触发为例,QApplication.exec()
执行后将会监听操作系统事件队列,当鼠标事件发生时,事件将会发送到QPushButton的event()函数进行分发:
[cpp]  view plain copy
  1. QPushButton::event ->   
  2. QAbstractButton::event ->  
  3. QWidget::event [Dispatch event]:  
  4.     case QEvent::KeyPress: {  
  5.         QKeyEvent *k = (QKeyEvent *)event;  
  6.         bool res = false;  
  7.         if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) {  //### Add MetaModifier?  
  8.             if (k->key() == Qt::Key_Backtab  
  9.                 || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier)))  
  10.                 res = focusNextPrevChild(false);  
  11.             else if (k->key() == Qt::Key_Tab)  
  12.                 res = focusNextPrevChild(true);  
  13.             if (res)  
  14.                 break;  
  15.         }  
  16.         keyPressEvent(k);  
  17.   
  18. -> QPushButton::keyPressEvent  
  19. void QPushButton::keyPressEvent(QKeyEvent *e)   
  20. {   
  21. Q_D(QPushButton);   
  22. switch (e->key()) {   
  23. case Qt::Key_Enter:   
  24. case Qt::Key_Return:   
  25.   if (autoDefault() || d->defaultButton) {   
  26.   click();   
  27.   break;   
  28. }   
  29. // fall through   
  30. default:   
  31.   QAbstractButton::keyPressEvent(e);   
  32. }   
  33. }  
  34.   
  35. -> QAbstractButton::click:  
  36. void QAbstractButton::click()   
  37. {   
  38. if (!isEnabled())   
  39.   return;   
  40. Q_D(QAbstractButton);   
  41. QPointer<QAbstractButton> guard(this);   
  42. d->down = true;   
  43. d->emitPressed();   
  44. if (guard) {   
  45.   d->down = false;   
  46.   nextCheckState();   
  47.   if (guard)   
  48.    d->emitReleased();   
  49.   if (guard)   
  50.    d->emitClicked();   
  51. }   
  52. }  


3.SIGNAL-SLOT类的编译

关于Q_OBJECT宏以及SIGNAL,SLOT,emit等关键字奇怪的语法,其实他们是通过一个叫做MOC元对象编译器
的组件来进行预编译的,因此我们可以使用SIGNAL,SLOT,emit来清晰地连接各个信号槽,而非函数指针。
SIGNAL-SLOT使用很方便,但也是会损失一点执行效率,使用时要谨慎。


4.总结及学习资料

通过这个例子可以对Qt的SIGNAL-SLOT机制有个简单的了解,它可以减少对象间的依赖。假如不使用它,我们就
需要在AddressBar中直接调用HtmlView的load()函数,两个类耦合在了一起。在这个例子中MainWindow负责AddressBar
和HtmlView的构建和连接,使它们互相不知道对方的存在!

让我更感兴趣的其实是QtWebKit,通过它我们可以在Qt开发桌面应用时使用Web技术,而不用局限于Qt,MFC等等。
Web开发人员也可以投身桌面应用开发之中。

QtWebKit官方文档:http://doc.qt.nokia.com/4.7-snapshot/qtwebkit.html
学习笔记:http://caterpillar.onlyfun.net/Gossip/Qt4Gossip/Qt4Gossip.html
QtWebKit系列教程:http://software.intel.com/zh-cn/blogs/2010/06/08/qt-webkit-qt-webkit/
信号槽深入学习:http://www.ibm.com/developerworks/cn/linux/guitoolkit/qt/signal-slot/
QtWeb - 一个开源的Qt浏览器项目




http://blog.csdn.net/dc_726/article/details/7600192


1.代码实现

工程目录结构如下:



AddressBar类包含了地址栏和按钮两个控件,将地址栏回车和按钮点击信号与goToSite()槽连接。
当回车和点击事件发生时,goToSite()将获得Url地址并发送go(QUrl)信号。

addressbar.h
[cpp]  view plain copy
  1. #ifndef ADDRESSBAR_H  
  2. #define ADDRESSBAR_H  
  3.   
  4. #include <QWidget>  
  5. #include <QLineEdit>  
  6. #include <QPushButton>  
  7. #include <QHBoxLayout>  
  8. #include <QUrl>  
  9. #include <QString>  
  10.   
  11. class AddressBar : public QWidget  
  12. {  
  13.     Q_OBJECT  
  14. public:  
  15.     explicit AddressBar(QWidget *parent = 0);      
  16.       
  17. signals:  
  18.     void go(QUrl);  
  19.       
  20. public slots:  
  21.     void goToSite();  
  22.   
  23. private:  
  24.     QLineEdit *addressEdit;  
  25.     QPushButton *goButton;  
  26.     QHBoxLayout *layout;  
  27. };  
  28.   
  29. #endif // ADDRESSBAR_H  

addressbar.cpp
[cpp]  view plain copy
  1. #include "addressbar.h"  
  2.   
  3. AddressBar::AddressBar(QWidget *parent) :  
  4.     QWidget(parent)  
  5. {  
  6.     addressEdit = new QLineEdit(parent);  
  7.     goButton = new QPushButton("Go", parent);  
  8.   
  9.     layout = new QHBoxLayout;  
  10.     layout->addWidget(addressEdit);  
  11.     layout->addWidget(goButton);  
  12.     this->setLayout(layout);  
  13.   
  14.     connect(goButton, SIGNAL(clicked()), this, SLOT(goToSite()));  
  15.     connect(addressEdit, SIGNAL(returnPressed()), this, SLOT(goToSite()));  
  16. }  
  17.   
  18. void AddressBar::goToSite()  
  19. {  
  20.     QString address = addressEdit->text();  
  21.     emit go(QUrl(address));  
  22. }  

接下来是QtWebkit包中的主要类QWebView,我们借助这个类来渲染Url指向的网页。
为了当用户在地址栏回车或者点击Go按钮时能够自动加载网页,我们需要给QWebView
添加loadNewPage(QUrl)槽(因为QWebView没有类似load(QUrl)的槽),并将其与go(QUrl)
信号连接。所以我们实现一个QWebView的子类HtmlView。

htmlview.h
[cpp]  view plain copy
  1. #ifndef HTMLVIEW_H  
  2. #define HTMLVIEW_H  
  3.   
  4. #include <QWebView>  
  5.   
  6. class HtmlView : public QWebView  
  7. {  
  8.     Q_OBJECT  
  9. public:  
  10.     explicit HtmlView(QWidget *parent = 0);  
  11.       
  12. signals:  
  13.       
  14. public slots:  
  15.     void loadNewPage(const QUrl &url);  
  16.       
  17. };  
  18.   
  19. #endif // HTMLVIEW_H  

htmlview.cpp
[cpp]  view plain copy
  1. #include "htmlview.h"  
  2.   
  3. HtmlView::HtmlView(QWidget *parent) :  
  4.     QWebView(parent)  
  5. {  
  6. }  
  7.   
  8. void HtmlView::loadNewPage(const QUrl &url)  
  9. {  
  10.     this->load(url);  
  11. }  

接下来实现程序的主窗口QMainWindow,将AddressBar和HtmlView放置其中。

mainwindow.h
[cpp]  view plain copy
  1. #ifndef MAINWINDOW_H  
  2. #define MAINWINDOW_H  
  3.   
  4. #include <QWidget>  
  5. #include <QLineEdit>  
  6. #include <QPushButton>  
  7. #include <QGridLayout>  
  8. #include <QtWebKit>  
  9. #include <QMainWindow>  
  10. #include "addressbar.h"  
  11. #include "htmlview.h"  
  12.   
  13. class MainWindow : public QMainWindow  
  14. {  
  15.     Q_OBJECT  
  16.       
  17. public:  
  18.     explicit MainWindow(QWidget *parent = 0);  
  19.   
  20. };  
  21.   
  22. #endif // MAINWINDOW_H  

mainwindow.cpp
[cpp]  view plain copy
  1. #include "mainwindow.h"  
  2. #include "ui_mainwindow.h"  
  3.   
  4. MainWindow::MainWindow(QWidget *parent) :  
  5.     QMainWindow(parent)  
  6. {  
  7.     // 1.Create widget  
  8.     QWidget *centralWidget = new QWidget(this);  
  9.     AddressBar *bar = new AddressBar;  
  10.     HtmlView *view = new HtmlView;  
  11.   
  12.     // 2.Add widget to layout  
  13.     QGridLayout *layout = new QGridLayout;  
  14.     layout->addWidget(bar, 0, 0, 1, 10);  
  15.     layout->addWidget(view, 1, 0, 1, 10);  
  16.     centralWidget->setLayout(layout);  
  17.   
  18.     // 3.Connect widget  
  19.     QObject::connect(bar, SIGNAL(go(QUrl)), view, SLOT(loadNewPage(QUrl)));  
  20.   
  21.     this->setCentralWidget(centralWidget);  
  22.     this->setWindowTitle("My Browser v1.0");  
  23.     this->resize(640, 480);  
  24. }  

最后是程序的入口main.cpp
[cpp]  view plain copy
  1. #include <QApplication>  
  2. #include "mainwindow.h"  
  3.   
  4. int main(int argc, char *argv[])  
  5. {  
  6.     QApplication app(argc, argv);  
  7.   
  8.     MainWindow *window = new MainWindow;  
  9.     window->show();  
  10.       
  11.     return app.exec();  
  12. }  


2.事件流分析



我们分别为AddressBar和HtmlView自定义了两个槽goToSite(QUrl)和loadNewPage(QUrl),以及新的信号go(QUrl)。
就是为了将Url地址传递给QWebView的load函数。

这里需要注意的是SIGNAL-SLOT机制是Qt的内部机制,它是同步执行的。源头上returnPressed()和clicked()槽的触发,
是从操作系统的事件队列中得到的,并进行异步的处理。以QPushButton的clicked()槽的触发为例,QApplication.exec()
执行后将会监听操作系统事件队列,当鼠标事件发生时,事件将会发送到QPushButton的event()函数进行分发:
[cpp]  view plain copy
  1. QPushButton::event ->   
  2. QAbstractButton::event ->  
  3. QWidget::event [Dispatch event]:  
  4.     case QEvent::KeyPress: {  
  5.         QKeyEvent *k = (QKeyEvent *)event;  
  6.         bool res = false;  
  7.         if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) {  //### Add MetaModifier?  
  8.             if (k->key() == Qt::Key_Backtab  
  9.                 || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier)))  
  10.                 res = focusNextPrevChild(false);  
  11.             else if (k->key() == Qt::Key_Tab)  
  12.                 res = focusNextPrevChild(true);  
  13.             if (res)  
  14.                 break;  
  15.         }  
  16.         keyPressEvent(k);  
  17.   
  18. -> QPushButton::keyPressEvent  
  19. void QPushButton::keyPressEvent(QKeyEvent *e)   
  20. {   
  21. Q_D(QPushButton);   
  22. switch (e->key()) {   
  23. case Qt::Key_Enter:   
  24. case Qt::Key_Return:   
  25.   if (autoDefault() || d->defaultButton) {   
  26.   click();   
  27.   break;   
  28. }   
  29. // fall through   
  30. default:   
  31.   QAbstractButton::keyPressEvent(e);   
  32. }   
  33. }  
  34.   
  35. -> QAbstractButton::click:  
  36. void QAbstractButton::click()   
  37. {   
  38. if (!isEnabled())   
  39.   return;   
  40. Q_D(QAbstractButton);   
  41. QPointer<QAbstractButton> guard(this);   
  42. d->down = true;   
  43. d->emitPressed();   
  44. if (guard) {   
  45.   d->down = false;   
  46.   nextCheckState();   
  47.   if (guard)   
  48.    d->emitReleased();   
  49.   if (guard)   
  50.    d->emitClicked();   
  51. }   
  52. }  


3.SIGNAL-SLOT类的编译

关于Q_OBJECT宏以及SIGNAL,SLOT,emit等关键字奇怪的语法,其实他们是通过一个叫做MOC元对象编译器
的组件来进行预编译的,因此我们可以使用SIGNAL,SLOT,emit来清晰地连接各个信号槽,而非函数指针。
SIGNAL-SLOT使用很方便,但也是会损失一点执行效率,使用时要谨慎。


4.总结及学习资料

通过这个例子可以对Qt的SIGNAL-SLOT机制有个简单的了解,它可以减少对象间的依赖。假如不使用它,我们就
需要在AddressBar中直接调用HtmlView的load()函数,两个类耦合在了一起。在这个例子中MainWindow负责AddressBar
和HtmlView的构建和连接,使它们互相不知道对方的存在!

让我更感兴趣的其实是QtWebKit,通过它我们可以在Qt开发桌面应用时使用Web技术,而不用局限于Qt,MFC等等。
Web开发人员也可以投身桌面应用开发之中。

QtWebKit官方文档:http://doc.qt.nokia.com/4.7-snapshot/qtwebkit.html
学习笔记:http://caterpillar.onlyfun.net/Gossip/Qt4Gossip/Qt4Gossip.html
QtWebKit系列教程:http://software.intel.com/zh-cn/blogs/2010/06/08/qt-webkit-qt-webkit/
信号槽深入学习:http://www.ibm.com/developerworks/cn/linux/guitoolkit/qt/signal-slot/
QtWeb - 一个开源的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]  view plain copy
  1. <html>  
  2.   
  3. <head>      
  4.     <meta http-equiv="Content-Type" content="text/html; charset=GB2312"/>  
  5.     <link rel="stylesheet" type="text/css" href="qrc:/style/style.css"/>  
  6.     <script type="text/javascript" src="qrc:/script/jquery-1.7.2.min.js"></script>  
  7.     <script type="text/javascript">  
  8.         function init() {             
  9.             $("#loadingdiv").html("正在加载城市天气预报...");  
  10.               
  11.             $.getJSON("http://m.weather.com.cn/data/101010100.html",  
  12.                 function(data) {  
  13.                     $("#loadingdiv").html("");  
  14.                     var weatherinfo = data["weatherinfo"];    
  15.                     var datearray = ["", weatherinfo["date_y"], "第二天", "第三天", "第四天", "第五天", "第六天"];    
  16.                     $("#cityname").html(weatherinfo["city"] + "城市天气预报");    
  17.                     for (i = 1; i <= 6; i++) {    
  18.                         var divid = "#div" + i;                
  19.                         $(divid).append(datearray[i]).append("<br>");    
  20.                         var imgurl = "http://m.weather.com.cn/weather_img/" + weatherinfo["img"+(i*2-1)] + ".gif";                   
  21.                         $(divid).append('<img src="' + imgurl + '"/>').append("<br>");    
  22.                         $(divid).append(weatherinfo["temp" + i]).append("<br>");    
  23.                         $(divid).append(weatherinfo["weather" + i]);                   
  24.                     }  
  25.                 }  
  26.             );            
  27.         }  
  28.     </script>  
  29. </head>  
  30.   
  31. <body onload="init()">  
  32.     <h1>Welcome!!!</h1>  
  33.       
  34.     <div id="weatherreportdiv">  
  35.         <div id="loadingdiv"></div>  
  36.         <div id="cityname"></div>    
  37.         <hr></hr>  
  38.         <div id="div1" class="weatherdiv"></div>    
  39.         <div id="div2" class="weatherdiv"></div>    
  40.         <div id="div3" class="weatherdiv"></div>    
  41.         <div id="div4" class="weatherdiv"></div>    
  42.         <div id="div5" class="weatherdiv"></div>    
  43.         <div id="div6" class="weatherdiv"></div>    
  44.     </div>  
  45.   
  46. </body>  
  47.   
  48. </html>  

style.css
[html]  view plain copy
  1. h1 {  
  2.     text-align: center;  
  3. }  
  4.   
  5. #weatherreportdiv {  
  6.     height: 300px;  
  7.     width: 700px;  
  8.     text-align: center;    
  9.     font-size: 20px;    
  10.     font-weight: bold;    
  11.     margin: 5px;    
  12. }  
  13.   
  14. #cityname {    
  15.     text-align: center;    
  16.     font-size: 20px;    
  17.     font-weight: bold;    
  18.     margin: 5px;    
  19. }    
  20.    
  21. .weatherdiv {    
  22.     float: left;    
  23.     width: 15%;    
  24.     margin: 5px;    
  25. }  

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


三、源码实现

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

addressbar.h
[cpp]  view plain copy
  1. #ifndef ADDRESSBAR_H  
  2. #define ADDRESSBAR_H  
  3.   
  4. #include <QWidget>  
  5. #include <QLineEdit>  
  6. #include <QPushButton>  
  7. #include <QHBoxLayout>  
  8. #include <QUrl>  
  9. #include <QString>  
  10.   
  11. class AddressBar : public QWidget  
  12. {  
  13.     Q_OBJECT  
  14. public:  
  15.     explicit AddressBar(QWidget *parent = 0);      
  16.       
  17. signals:  
  18.     void go(const QUrl&);  
  19.     void back();  
  20.     void forward();  
  21.     void newPage();  
  22.       
  23. public slots:  
  24.     void handleGoToSite();  
  25.     void handleAddressChanged(const QUrl&);  
  26.   
  27. private:  
  28.     QLineEdit *addressEdit;  
  29.     QPushButton *newButton;  
  30.     QPushButton *backButton;  
  31.     QPushButton *forwardButton;  
  32.     QPushButton *goButton;  
  33.     QHBoxLayout *layout;  
  34. };  
  35.   
  36. #endif // ADDRESSBAR_H  

addressbar.cpp
[cpp]  view plain copy
  1. #include "addressbar.h"  
  2.   
  3. AddressBar::AddressBar(QWidget *parent) :  
  4.     QWidget(parent)  
  5. {  
  6.     // 1.Create widget  
  7.     addressEdit = new QLineEdit;  
  8.     newButton = new QPushButton("New");  
  9.     backButton = new QPushButton("Back");  
  10.     forwardButton = new QPushButton("Forward");  
  11.     goButton = new QPushButton("Go");  
  12.   
  13.     // 2.Set property  
  14.   
  15.     // 3.Connect signal and slot  
  16.     connect(goButton, SIGNAL(clicked()), this, SLOT(handleGoToSite()));  
  17.     connect(addressEdit, SIGNAL(returnPressed()), this, SLOT(handleGoToSite()));  
  18.     connect(backButton, SIGNAL(clicked()), this, SIGNAL(back()));  
  19.     connect(forwardButton, SIGNAL(clicked()), this, SIGNAL(forward()));  
  20.     connect(newButton, SIGNAL(clicked()), this, SIGNAL(newPage()));  
  21.   
  22.     // 4.Add to layout  
  23.     layout = new QHBoxLayout;  
  24.     layout->addWidget(newButton);  
  25.     layout->addWidget(backButton);  
  26.     layout->addWidget(forwardButton);  
  27.     layout->addWidget(addressEdit);  
  28.     layout->addWidget(goButton);  
  29.     this->setLayout(layout);  
  30. }  
  31.   
  32. void AddressBar::handleGoToSite()  
  33. {  
  34.     QString address = addressEdit->text();  
  35.     emit go(QUrl(address));  
  36. }  
  37.   
  38. void AddressBar::handleAddressChanged(const QUrl &url)  
  39. {  
  40.     addressEdit->setText(url.toString());  
  41. }  

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

tabpage.h
[cpp]  view plain copy
  1. #ifndef TABPAGE_H  
  2. #define TABPAGE_H  
  3.   
  4. #include <QTabWidget>  
  5. #include <QList>  
  6. #include "htmlview.h"  
  7.   
  8. class TabPage : public QTabWidget  
  9. {  
  10.     Q_OBJECT  
  11. public:  
  12.     explicit TabPage(QWidget *parent = 0);  
  13.     ~TabPage();  
  14.       
  15. signals:  
  16.     void urlChanged(const QUrl&);  
  17.       
  18. public slots:  
  19.     void handleNewTab();  
  20.     void handleLoadNewPage(const QUrl&);  
  21.     void handleBack();  
  22.     void handleForward();  
  23.   
  24. private slots:  
  25.     void handleTabChanged(int);  
  26.     void handleTabClosed(int);  
  27.     void handleLinkClicked(const QUrl&);  
  28.   
  29. private:      
  30.     QList<QWebView*> viewList;  
  31. };  
  32.   
  33. #endif // TABPAGE_H  

tabpage.cpp
[cpp]  view plain copy
  1. #include "tabpage.h"  
  2. #include <QtDebug>  
  3.   
  4. TabPage::TabPage(QWidget *parent) :  
  5.     QTabWidget(parent)  
  6. {  
  7.     // Set property  
  8.     this->setTabsClosable(true);  
  9.   
  10.     // Connect built-in signal to customized one to convert index to url  
  11.     connect(this, SIGNAL(currentChanged(int)), SLOT(handleTabChanged(int)));  
  12.     connect(this, SIGNAL(tabCloseRequested(int)), this, SLOT(handleTabClosed(int)));  
  13.   
  14.     // Create new tab for home page  
  15.     this->handleNewTab();  
  16. }  
  17.   
  18. TabPage::~TabPage()  
  19. {      
  20. }  
  21.   
  22. void TabPage::handleNewTab()  
  23. {  
  24.     HtmlView *view = new HtmlView;  
  25.     view->load(QUrl("qrc:/html/welcome.html"));  
  26.     //view->page()->setForwardUnsupportedContent(true);  
  27.     view->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);  
  28.   
  29.     // Monitor linkClicked signal      
  30.     connect(view, SIGNAL(linkClicked(const QUrl&)), this, SLOT(handleLinkClicked(const QUrl&)));      
  31.   
  32.     // Add and activate this new tab  
  33.     int index = this->addTab(view, "Welcome");  
  34.     this->setCurrentIndex(index);  
  35.   
  36.     viewList.append(view);  
  37. }  
  38.   
  39. void TabPage::handleLoadNewPage(const QUrl &url)  
  40. {  
  41.     qDebug() << "loadNewPage: " << url.toString();  
  42.     HtmlView *view = (HtmlView*) this->currentWidget();  
  43.     view->load(url);  
  44. }  
  45.   
  46. void TabPage::handleBack()  
  47. {  
  48.     HtmlView *view = (HtmlView*) this->currentWidget();  
  49.     view->back();  
  50.     emit urlChanged(view->url());  
  51. }  
  52.   
  53. void TabPage::handleForward()  
  54. {  
  55.     HtmlView *view = (HtmlView*) this->currentWidget();  
  56.     view->forward();  
  57.     emit urlChanged(view->url());  
  58. }  
  59.   
  60. void TabPage::handleTabChanged(int index)  
  61. {  
  62.     if (index > viewList.length() - 1)  
  63.         return;  
  64.   
  65.     // index is the new tab index  
  66.     QWebView* view = viewList[index];  
  67.     emit urlChanged(view->url());  
  68. }  
  69.   
  70. void TabPage::handleTabClosed(int index)  
  71. {  
  72.     if (index > viewList.length() - 1)  
  73.         return;  
  74.   
  75.     this->removeTab(index);  
  76.     QWebView* view = viewList[index];  
  77.     viewList.removeAt(index);  
  78.   
  79.     delete view;  
  80. }  
  81.   
  82. void TabPage::handleLinkClicked(const QUrl& url)  
  83. {  
  84.     qDebug() << "handleLinkClicked: " << url.toString();  
  85.     HtmlView *view = (HtmlView*) this->currentWidget();  
  86.     view->load(url);  
  87.     emit urlChanged(url);  
  88. }  

接下来是MainWindow,改动很小。

mainwindow.h
[cpp]  view plain copy
  1. #ifndef MAINWINDOW_H  
  2. #define MAINWINDOW_H  
  3.   
  4. #include <QWidget>  
  5. #include <QLineEdit>  
  6. #include <QPushButton>  
  7. #include <QGridLayout>  
  8. #include <QtWebKit>  
  9. #include <QMainWindow>  
  10. #include "addressbar.h"  
  11. #include "htmlview.h"  
  12. #include "tabpage.h"  
  13.   
  14. namespace Ui {  
  15. class MainWindow;  
  16. }  
  17.   
  18. class MainWindow : public QMainWindow  
  19. {  
  20.     Q_OBJECT  
  21.       
  22. public:  
  23.     explicit MainWindow(QWidget *parent = 0);  
  24.     ~MainWindow();  
  25.       
  26. private:  
  27.     Ui::MainWindow *ui;      
  28. };  
  29.   
  30. #endif // MAINWINDOW_H  

mainwindow.cpp
[cpp]  view plain copy
  1. #include "mainwindow.h"  
  2. #include "ui_mainwindow.h"  
  3.   
  4. MainWindow::MainWindow(QWidget *parent) :  
  5.     QMainWindow(parent),  
  6.     ui(new Ui::MainWindow)  
  7. {  
  8.     //ui->setupUi(this);  
  9.     // 0.Global setting  
  10.     QWebSettings* defaultSettings = QWebSettings::globalSettings();  
  11.     // We use JavaScript, so set it to be enabled.  
  12.     defaultSettings->setAttribute(QWebSettings::JavascriptEnabled, true);  
  13.     // Plug-ins must be set to be enabled to use plug-ins.  
  14.     defaultSettings->setAttribute(QWebSettings::PluginsEnabled,true);  
  15.     defaultSettings->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls,true);  
  16.     defaultSettings->setObjectCacheCapacities(0, 0, 0);  
  17.   
  18.     // 1.Create widget  
  19.     QWidget *centralWidget = new QWidget(this);  
  20.     AddressBar *bar = new AddressBar;      
  21.     TabPage *tab = new TabPage;  
  22.   
  23.     // 2.Set property  
  24.     this->setCentralWidget(centralWidget);  
  25.     this->setWindowTitle("My Browser v1.0");  
  26.     this->resize(800, 600);  
  27.   
  28.     // 3.Connect widget          
  29.     QObject::connect(bar, SIGNAL(newPage()),tab, SLOT(handleNewTab()));  
  30.     QObject::connect(bar, SIGNAL(back()),tab, SLOT(handleBack()));  
  31.     QObject::connect(bar, SIGNAL(forward()),tab, SLOT(handleForward()));  
  32.     QObject::connect(bar, SIGNAL(go(QUrl)), tab, SLOT(handleLoadNewPage(QUrl)));  
  33.     QObject::connect(tab, SIGNAL(urlChanged(QUrl)), bar, SLOT(handleAddressChanged(QUrl)));  
  34.   
  35.     // 4.Add widget to layout  
  36.     QGridLayout *layout = new QGridLayout;  
  37.     layout->addWidget(bar, 0, 0, 1, 10);  
  38.     layout->addWidget(tab, 1, 0, 1, 10);  
  39.     centralWidget->setLayout(layout);  
  40. }  
  41.   
  42. MainWindow::~MainWindow()  
  43. {  
  44.     //delete ui;  
  45. }  


四、关键问题

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

[cpp]  view plain copy
  1. #ifndef HTMLVIEW_H  
  2. #define HTMLVIEW_H  
  3.   
  4. #include <QWebView>  
  5.   
  6. class HtmlView : public QWebView  
  7. {  
  8.     Q_OBJECT  
  9. public:  
  10.     explicit HtmlView(QWidget *parent = 0);  
  11.       
  12. signals:  
  13.       
  14. public slots:  
  15.     void loadNewPage(const QUrl &url);  
  16.       
  17. };  
  18.   
  19. #endif // HTMLVIEW_H  
htmlview.cpp

[cpp]  view plain copy
  1. #include "htmlview.h"  
  2.   
  3. HtmlView::HtmlView(QWidget *parent) :  
  4.     QWebView(parent)  
  5. {  
  6. }  
  7.   
  8. void HtmlView::loadNewPage(const QUrl &url)  
  9. {      
  10.     this->load(url);  
  11. }  

1.代码实现

工程目录结构如下:



AddressBar类包含了地址栏和按钮两个控件,将地址栏回车和按钮点击信号与goToSite()槽连接。
当回车和点击事件发生时,goToSite()将获得Url地址并发送go(QUrl)信号。

addressbar.h
[cpp]  view plain copy
  1. #ifndef ADDRESSBAR_H  
  2. #define ADDRESSBAR_H  
  3.   
  4. #include <QWidget>  
  5. #include <QLineEdit>  
  6. #include <QPushButton>  
  7. #include <QHBoxLayout>  
  8. #include <QUrl>  
  9. #include <QString>  
  10.   
  11. class AddressBar : public QWidget  
  12. {  
  13.     Q_OBJECT  
  14. public:  
  15.     explicit AddressBar(QWidget *parent = 0);      
  16.       
  17. signals:  
  18.     void go(QUrl);  
  19.       
  20. public slots:  
  21.     void goToSite();  
  22.   
  23. private:  
  24.     QLineEdit *addressEdit;  
  25.     QPushButton *goButton;  
  26.     QHBoxLayout *layout;  
  27. };  
  28.   
  29. #endif // ADDRESSBAR_H  

addressbar.cpp
[cpp]  view plain copy
  1. #include "addressbar.h"  
  2.   
  3. AddressBar::AddressBar(QWidget *parent) :  
  4.     QWidget(parent)  
  5. {  
  6.     addressEdit = new QLineEdit(parent);  
  7.     goButton = new QPushButton("Go", parent);  
  8.   
  9.     layout = new QHBoxLayout;  
  10.     layout->addWidget(addressEdit);  
  11.     layout->addWidget(goButton);  
  12.     this->setLayout(layout);  
  13.   
  14.     connect(goButton, SIGNAL(clicked()), this, SLOT(goToSite()));  
  15.     connect(addressEdit, SIGNAL(returnPressed()), this, SLOT(goToSite()));  
  16. }  
  17.   
  18. void AddressBar::goToSite()  
  19. {  
  20.     QString address = addressEdit->text();  
  21.     emit go(QUrl(address));  
  22. }  

接下来是QtWebkit包中的主要类QWebView,我们借助这个类来渲染Url指向的网页。
为了当用户在地址栏回车或者点击Go按钮时能够自动加载网页,我们需要给QWebView
添加loadNewPage(QUrl)槽(因为QWebView没有类似load(QUrl)的槽),并将其与go(QUrl)
信号连接。所以我们实现一个QWebView的子类HtmlView。

htmlview.h
[cpp]  view plain copy
  1. #ifndef HTMLVIEW_H  
  2. #define HTMLVIEW_H  
  3.   
  4. #include <QWebView>  
  5.   
  6. class HtmlView : public QWebView  
  7. {  
  8.     Q_OBJECT  
  9. public:  
  10.     explicit HtmlView(QWidget *parent = 0);  
  11.       
  12. signals:  
  13.       
  14. public slots:  
  15.     void loadNewPage(const QUrl &url);  
  16.       
  17. };  
  18.   
  19. #endif // HTMLVIEW_H  

htmlview.cpp
[cpp]  view plain copy
  1. #include "htmlview.h"  
  2.   
  3. HtmlView::HtmlView(QWidget *parent) :  
  4.     QWebView(parent)  
  5. {  
  6. }  
  7.   
  8. void HtmlView::loadNewPage(const QUrl &url)  
  9. {  
  10.     this->load(url);  
  11. }  

接下来实现程序的主窗口QMainWindow,将AddressBar和HtmlView放置其中。

mainwindow.h
[cpp]  view plain copy
  1. #ifndef MAINWINDOW_H  
  2. #define MAINWINDOW_H  
  3.   
  4. #include <QWidget>  
  5. #include <QLineEdit>  
  6. #include <QPushButton>  
  7. #include <QGridLayout>  
  8. #include <QtWebKit>  
  9. #include <QMainWindow>  
  10. #include "addressbar.h"  
  11. #include "htmlview.h"  
  12.   
  13. class MainWindow : public QMainWindow  
  14. {  
  15.     Q_OBJECT  
  16.       
  17. public:  
  18.     explicit MainWindow(QWidget *parent = 0);  
  19.   
  20. };  
  21.   
  22. #endif // MAINWINDOW_H  

mainwindow.cpp
[cpp]  view plain copy
  1. #include "mainwindow.h"  
  2. #include "ui_mainwindow.h"  
  3.   
  4. MainWindow::MainWindow(QWidget *parent) :  
  5.     QMainWindow(parent)  
  6. {  
  7.     // 1.Create widget  
  8.     QWidget *centralWidget = new QWidget(this);  
  9.     AddressBar *bar = new AddressBar;  
  10.     HtmlView *view = new HtmlView;  
  11.   
  12.     // 2.Add widget to layout  
  13.     QGridLayout *layout = new QGridLayout;  
  14.     layout->addWidget(bar, 0, 0, 1, 10);  
  15.     layout->addWidget(view, 1, 0, 1, 10);  
  16.     centralWidget->setLayout(layout);  
  17.   
  18.     // 3.Connect widget  
  19.     QObject::connect(bar, SIGNAL(go(QUrl)), view, SLOT(loadNewPage(QUrl)));  
  20.   
  21.     this->setCentralWidget(centralWidget);  
  22.     this->setWindowTitle("My Browser v1.0");  
  23.     this->resize(640, 480);  
  24. }  

最后是程序的入口main.cpp
[cpp]  view plain copy
  1. #include <QApplication>  
  2. #include "mainwindow.h"  
  3.   
  4. int main(int argc, char *argv[])  
  5. {  
  6.     QApplication app(argc, argv);  
  7.   
  8.     MainWindow *window = new MainWindow;  
  9.     window->show();  
  10.       
  11.     return app.exec();  
  12. }  


2.事件流分析



我们分别为AddressBar和HtmlView自定义了两个槽goToSite(QUrl)和loadNewPage(QUrl),以及新的信号go(QUrl)。
就是为了将Url地址传递给QWebView的load函数。

这里需要注意的是SIGNAL-SLOT机制是Qt的内部机制,它是同步执行的。源头上returnPressed()和clicked()槽的触发,
是从操作系统的事件队列中得到的,并进行异步的处理。以QPushButton的clicked()槽的触发为例,QApplication.exec()
执行后将会监听操作系统事件队列,当鼠标事件发生时,事件将会发送到QPushButton的event()函数进行分发:
[cpp]  view plain copy
  1. QPushButton::event ->   
  2. QAbstractButton::event ->  
  3. QWidget::event [Dispatch event]:  
  4.     case QEvent::KeyPress: {  
  5.         QKeyEvent *k = (QKeyEvent *)event;  
  6.         bool res = false;  
  7.         if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) {  //### Add MetaModifier?  
  8.             if (k->key() == Qt::Key_Backtab  
  9.                 || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier)))  
  10.                 res = focusNextPrevChild(false);  
  11.             else if (k->key() == Qt::Key_Tab)  
  12.                 res = focusNextPrevChild(true);  
  13.             if (res)  
  14.                 break;  
  15.         }  
  16.         keyPressEvent(k);  
  17.   
  18. -> QPushButton::keyPressEvent  
  19. void QPushButton::keyPressEvent(QKeyEvent *e)   
  20. {   
  21. Q_D(QPushButton);   
  22. switch (e->key()) {   
  23. case Qt::Key_Enter:   
  24. case Qt::Key_Return:   
  25.   if (autoDefault() || d->defaultButton) {   
  26.   click();   
  27.   break;   
  28. }   
  29. // fall through   
  30. default:   
  31.   QAbstractButton::keyPressEvent(e);   
  32. }   
  33. }  
  34.   
  35. -> QAbstractButton::click:  
  36. void QAbstractButton::click()   
  37. {   
  38. if (!isEnabled())   
  39.   return;   
  40. Q_D(QAbstractButton);   
  41. QPointer<QAbstractButton> guard(this);   
  42. d->down = true;   
  43. d->emitPressed();   
  44. if (guard) {   
  45.   d->down = false;   
  46.   nextCheckState();   
  47.   if (guard)   
  48.    d->emitReleased();   
  49.   if (guard)   
  50.    d->emitClicked();   
  51. }   
  52. }  


3.SIGNAL-SLOT类的编译

关于Q_OBJECT宏以及SIGNAL,SLOT,emit等关键字奇怪的语法,其实他们是通过一个叫做MOC元对象编译器
的组件来进行预编译的,因此我们可以使用SIGNAL,SLOT,emit来清晰地连接各个信号槽,而非函数指针。
SIGNAL-SLOT使用很方便,但也是会损失一点执行效率,使用时要谨慎。


4.总结及学习资料

通过这个例子可以对Qt的SIGNAL-SLOT机制有个简单的了解,它可以减少对象间的依赖。假如不使用它,我们就
需要在AddressBar中直接调用HtmlView的load()函数,两个类耦合在了一起。在这个例子中MainWindow负责AddressBar
和HtmlView的构建和连接,使它们互相不知道对方的存在!

让我更感兴趣的其实是QtWebKit,通过它我们可以在Qt开发桌面应用时使用Web技术,而不用局限于Qt,MFC等等。
Web开发人员也可以投身桌面应用开发之中。

QtWebKit官方文档:http://doc.qt.nokia.com/4.7-snapshot/qtwebkit.html
学习笔记:http://caterpillar.onlyfun.net/Gossip/Qt4Gossip/Qt4Gossip.html
QtWebKit系列教程:http://software.intel.com/zh-cn/blogs/2010/06/08/qt-webkit-qt-webkit/
信号槽深入学习:http://www.ibm.com/developerworks/cn/linux/guitoolkit/qt/signal-slot/
QtWeb - 一个开源的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]  view plain copy
  1. <html>  
  2.   
  3. <head>      
  4.     <meta http-equiv="Content-Type" content="text/html; charset=GB2312"/>  
  5.     <link rel="stylesheet" type="text/css" href="qrc:/style/style.css"/>  
  6.     <script type="text/javascript" src="qrc:/script/jquery-1.7.2.min.js"></script>  
  7.     <script type="text/javascript">  
  8.         function init() {             
  9.             $("#loadingdiv").html("正在加载城市天气预报...");  
  10.               
  11.             $.getJSON("http://m.weather.com.cn/data/101010100.html",  
  12.                 function(data) {  
  13.                     $("#loadingdiv").html("");  
  14.                     var weatherinfo = data["weatherinfo"];    
  15.                     var datearray = ["", weatherinfo["date_y"], "第二天", "第三天", "第四天", "第五天", "第六天"];    
  16.                     $("#cityname").html(weatherinfo["city"] + "城市天气预报");    
  17.                     for (i = 1; i <= 6; i++) {    
  18.                         var divid = "#div" + i;                
  19.                         $(divid).append(datearray[i]).append("<br>");    
  20.                         var imgurl = "http://m.weather.com.cn/weather_img/" + weatherinfo["img"+(i*2-1)] + ".gif";                   
  21.                         $(divid).append('<img src="' + imgurl + '"/>').append("<br>");    
  22.                         $(divid).append(weatherinfo["temp" + i]).append("<br>");    
  23.                         $(divid).append(weatherinfo["weather" + i]);                   
  24.                     }  
  25.                 }  
  26.             );            
  27.         }  
  28.     </script>  
  29. </head>  
  30.   
  31. <body onload="init()">  
  32.     <h1>Welcome!!!</h1>  
  33.       
  34.     <div id="weatherreportdiv">  
  35.         <div id="loadingdiv"></div>  
  36.         <div id="cityname"></div>    
  37.         <hr></hr>  
  38.         <div id="div1" class="weatherdiv"></div>    
  39.         <div id="div2" class="weatherdiv"></div>    
  40.         <div id="div3" class="weatherdiv"></div>    
  41.         <div id="div4" class="weatherdiv"></div>    
  42.         <div id="div5" class="weatherdiv"></div>    
  43.         <div id="div6" class="weatherdiv"></div>    
  44.     </div>  
  45.   
  46. </body>  
  47.   
  48. </html>  

style.css
[html]  view plain copy
  1. h1 {  
  2.     text-align: center;  
  3. }  
  4.   
  5. #weatherreportdiv {  
  6.     height: 300px;  
  7.     width: 700px;  
  8.     text-align: center;    
  9.     font-size: 20px;    
  10.     font-weight: bold;    
  11.     margin: 5px;    
  12. }  
  13.   
  14. #cityname {    
  15.     text-align: center;    
  16.     font-size: 20px;    
  17.     font-weight: bold;    
  18.     margin: 5px;    
  19. }    
  20.    
  21. .weatherdiv {    
  22.     float: left;    
  23.     width: 15%;    
  24.     margin: 5px;    
  25. }  

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


三、源码实现

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

addressbar.h
[cpp]  view plain copy
  1. #ifndef ADDRESSBAR_H  
  2. #define ADDRESSBAR_H  
  3.   
  4. #include <QWidget>  
  5. #include <QLineEdit>  
  6. #include <QPushButton>  
  7. #include <QHBoxLayout>  
  8. #include <QUrl>  
  9. #include <QString>  
  10.   
  11. class AddressBar : public QWidget  
  12. {  
  13.     Q_OBJECT  
  14. public:  
  15.     explicit AddressBar(QWidget *parent = 0);      
  16.       
  17. signals:  
  18.     void go(const QUrl&);  
  19.     void back();  
  20.     void forward();  
  21.     void newPage();  
  22.       
  23. public slots:  
  24.     void handleGoToSite();  
  25.     void handleAddressChanged(const QUrl&);  
  26.   
  27. private:  
  28.     QLineEdit *addressEdit;  
  29.     QPushButton *newButton;  
  30.     QPushButton *backButton;  
  31.     QPushButton *forwardButton;  
  32.     QPushButton *goButton;  
  33.     QHBoxLayout *layout;  
  34. };  
  35.   
  36. #endif // ADDRESSBAR_H  

addressbar.cpp
[cpp]  view plain copy
  1. #include "addressbar.h"  
  2.   
  3. AddressBar::AddressBar(QWidget *parent) :  
  4.     QWidget(parent)  
  5. {  
  6.     // 1.Create widget  
  7.     addressEdit = new QLineEdit;  
  8.     newButton = new QPushButton("New");  
  9.     backButton = new QPushButton("Back");  
  10.     forwardButton = new QPushButton("Forward");  
  11.     goButton = new QPushButton("Go");  
  12.   
  13.     // 2.Set property  
  14.   
  15.     // 3.Connect signal and slot  
  16.     connect(goButton, SIGNAL(clicked()), this, SLOT(handleGoToSite()));  
  17.     connect(addressEdit, SIGNAL(returnPressed()), this, SLOT(handleGoToSite()));  
  18.     connect(backButton, SIGNAL(clicked()), this, SIGNAL(back()));  
  19.     connect(forwardButton, SIGNAL(clicked()), this, SIGNAL(forward()));  
  20.     connect(newButton, SIGNAL(clicked()), this, SIGNAL(newPage()));  
  21.   
  22.     // 4.Add to layout  
  23.     layout = new QHBoxLayout;  
  24.     layout->addWidget(newButton);  
  25.     layout->addWidget(backButton);  
  26.     layout->addWidget(forwardButton);  
  27.     layout->addWidget(addressEdit);  
  28.     layout->addWidget(goButton);  
  29.     this->setLayout(layout);  
  30. }  
  31.   
  32. void AddressBar::handleGoToSite()  
  33. {  
  34.     QString address = addressEdit->text();  
  35.     emit go(QUrl(address));  
  36. }  
  37.   
  38. void AddressBar::handleAddressChanged(const QUrl &url)  
  39. {  
  40.     addressEdit->setText(url.toString());  
  41. }  

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

tabpage.h
[cpp]  view plain copy
  1. #ifndef TABPAGE_H  
  2. #define TABPAGE_H  
  3.   
  4. #include <QTabWidget>  
  5. #include <QList>  
  6. #include "htmlview.h"  
  7.   
  8. class TabPage : public QTabWidget  
  9. {  
  10.     Q_OBJECT  
  11. public:  
  12.     explicit TabPage(QWidget *parent = 0);  
  13.     ~TabPage();  
  14.       
  15. signals:  
  16.     void urlChanged(const QUrl&);  
  17.       
  18. public slots:  
  19.     void handleNewTab();  
  20.     void handleLoadNewPage(const QUrl&);  
  21.     void handleBack();  
  22.     void handleForward();  
  23.   
  24. private slots:  
  25.     void handleTabChanged(int);  
  26.     void handleTabClosed(int);  
  27.     void handleLinkClicked(const QUrl&);  
  28.   
  29. private:      
  30.     QList<QWebView*> viewList;  
  31. };  
  32.   
  33. #endif // TABPAGE_H  

tabpage.cpp
[cpp]  view plain copy
  1. #include "tabpage.h"  
  2. #include <QtDebug>  
  3.   
  4. TabPage::TabPage(QWidget *parent) :  
  5.     QTabWidget(parent)  
  6. {  
  7.     // Set property  
  8.     this->setTabsClosable(true);  
  9.   
  10.     // Connect built-in signal to customized one to convert index to url  
  11.     connect(this, SIGNAL(currentChanged(int)), SLOT(handleTabChanged(int)));  
  12.     connect(this, SIGNAL(tabCloseRequested(int)), this, SLOT(handleTabClosed(int)));  
  13.   
  14.     // Create new tab for home page  
  15.     this->handleNewTab();  
  16. }  
  17.   
  18. TabPage::~TabPage()  
  19. {      
  20. }  
  21.   
  22. void TabPage::handleNewTab()  
  23. {  
  24.     HtmlView *view = new HtmlView;  
  25.     view->load(QUrl("qrc:/html/welcome.html"));  
  26.     //view->page()->setForwardUnsupportedContent(true);  
  27.     view->page()->setLinkDelegationPolicy(QWebPage::DelegateAllLinks);  
  28.   
  29.     // Monitor linkClicked signal      
  30.     connect(view, SIGNAL(linkClicked(const QUrl&)), this, SLOT(handleLinkClicked(const QUrl&)));      
  31.   
  32.     // Add and activate this new tab  
  33.     int index = this->addTab(view, "Welcome");  
  34.     this->setCurrentIndex(index);  
  35.   
  36.     viewList.append(view);  
  37. }  
  38.   
  39. void TabPage::handleLoadNewPage(const QUrl &url)  
  40. {  
  41.     qDebug() << "loadNewPage: " << url.toString();  
  42.     HtmlView *view = (HtmlView*) this->currentWidget();  
  43.     view->load(url);  
  44. }  
  45.   
  46. void TabPage::handleBack()  
  47. {  
  48.     HtmlView *view = (HtmlView*) this->currentWidget();  
  49.     view->back();  
  50.     emit urlChanged(view->url());  
  51. }  
  52.   
  53. void TabPage::handleForward()  
  54. {  
  55.     HtmlView *view = (HtmlView*) this->currentWidget();  
  56.     view->forward();  
  57.     emit urlChanged(view->url());  
  58. }  
  59.   
  60. void TabPage::handleTabChanged(int index)  
  61. {  
  62.     if (index > viewList.length() - 1)  
  63.         return;  
  64.   
  65.     // index is the new tab index  
  66.     QWebView* view = viewList[index];  
  67.     emit urlChanged(view->url());  
  68. }  
  69.   
  70. void TabPage::handleTabClosed(int index)  
  71. {  
  72.     if (index > viewList.length() - 1)  
  73.         return;  
  74.   
  75.     this->removeTab(index);  
  76.     QWebView* view = viewList[index];  
  77.     viewList.removeAt(index);  
  78.   
  79.     delete view;  
  80. }  
  81.   
  82. void TabPage::handleLinkClicked(const QUrl& url)  
  83. {  
  84.     qDebug() << "handleLinkClicked: " << url.toString();  
  85.     HtmlView *view = (HtmlView*) this->currentWidget();  
  86.     view->load(url);  
  87.     emit urlChanged(url);  
  88. }  

接下来是MainWindow,改动很小。

mainwindow.h
[cpp]  view plain copy
  1. #ifndef MAINWINDOW_H  
  2. #define MAINWINDOW_H  
  3.   
  4. #include <QWidget>  
  5. #include <QLineEdit>  
  6. #include <QPushButton>  
  7. #include <QGridLayout>  
  8. #include <QtWebKit>  
  9. #include <QMainWindow>  
  10. #include "addressbar.h"  
  11. #include "htmlview.h"  
  12. #include "tabpage.h"  
  13.   
  14. namespace Ui {  
  15. class MainWindow;  
  16. }  
  17.   
  18. class MainWindow : public QMainWindow  
  19. {  
  20.     Q_OBJECT  
  21.       
  22. public:  
  23.     explicit MainWindow(QWidget *parent = 0);  
  24.     ~MainWindow();  
  25.       
  26. private:  
  27.     Ui::MainWindow *ui;      
  28. };  
  29.   
  30. #endif // MAINWINDOW_H  

mainwindow.cpp
[cpp]  view plain copy
  1. #include "mainwindow.h"  
  2. #include "ui_mainwindow.h"  
  3.   
  4. MainWindow::MainWindow(QWidget *parent) :  
  5.     QMainWindow(parent),  
  6.     ui(new Ui::MainWindow)  
  7. {  
  8.     //ui->setupUi(this);  
  9.     // 0.Global setting  
  10.     QWebSettings* defaultSettings = QWebSettings::globalSettings();  
  11.     // We use JavaScript, so set it to be enabled.  
  12.     defaultSettings->setAttribute(QWebSettings::JavascriptEnabled, true);  
  13.     // Plug-ins must be set to be enabled to use plug-ins.  
  14.     defaultSettings->setAttribute(QWebSettings::PluginsEnabled,true);  
  15.     defaultSettings->setAttribute(QWebSettings::LocalContentCanAccessRemoteUrls,true);  
  16.     defaultSettings->setObjectCacheCapacities(0, 0, 0);  
  17.   
  18.     // 1.Create widget  
  19.     QWidget *centralWidget = new QWidget(this);  
  20.     AddressBar *bar = new AddressBar;      
  21.     TabPage *tab = new TabPage;  
  22.   
  23.     // 2.Set property  
  24.     this->setCentralWidget(centralWidget);  
  25.     this->setWindowTitle("My Browser v1.0");  
  26.     this->resize(800, 600);  
  27.   
  28.     // 3.Connect widget          
  29.     QObject::connect(bar, SIGNAL(newPage()),tab, SLOT(handleNewTab()));  
  30.     QObject::connect(bar, SIGNAL(back()),tab, SLOT(handleBack()));  
  31.     QObject::connect(bar, SIGNAL(forward()),tab, SLOT(handleForward()));  
  32.     QObject::connect(bar, SIGNAL(go(QUrl)), tab, SLOT(handleLoadNewPage(QUrl)));  
  33.     QObject::connect(tab, SIGNAL(urlChanged(QUrl)), bar, SLOT(handleAddressChanged(QUrl)));  
  34.   
  35.     // 4.Add widget to layout  
  36.     QGridLayout *layout = new QGridLayout;  
  37.     layout->addWidget(bar, 0, 0, 1, 10);  
  38.     layout->addWidget(tab, 1, 0, 1, 10);  
  39.     centralWidget->setLayout(layout);  
  40. }  
  41.   
  42. MainWindow::~MainWindow()  
  43. {  
  44.     //delete ui;  
  45. }  


四、关键问题

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

[cpp]  view plain copy
  1. #ifndef HTMLVIEW_H  
  2. #define HTMLVIEW_H  
  3.   
  4. #include <QWebView>  
  5.   
  6. class HtmlView : public QWebView  
  7. {  
  8.     Q_OBJECT  
  9. public:  
  10.     explicit HtmlView(QWidget *parent = 0);  
  11.       
  12. signals:  
  13.       
  14. public slots:  
  15.     void loadNewPage(const QUrl &url);  
  16.       
  17. };  
  18.   
  19. #endif // HTMLVIEW_H  
htmlview.cpp

[cpp]  view plain copy
  1. #include "htmlview.h"  
  2.   
  3. HtmlView::HtmlView(QWidget *parent) :  
  4.     QWebView(parent)  
  5. {  
  6. }  
  7.   
  8. void HtmlView::loadNewPage(const QUrl &url)  
  9. {      
  10.     this->load(url);  
  11. }  
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值