您的位置:首页 > 编程语言 > Qt开发

用QtWebKit开发简单的浏览器

2016-07-01 02:30 316 查看

用QtWebKit开发简单的浏览器

1.代码实现

工程目录结构如下:



AddressBar类包含了地址栏和按钮两个控件,将地址栏回车和按钮点击信号与goToSite()槽连接。

当回车和点击事件发生时,goToSite()将获得Url地址并发送go(QUrl)信号。

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(QUrl);

public slots:
void goToSite();

private:
QLineEdit *addressEdit;
QPushButton *goButton;
QHBoxLayout *layout;
};

#endif // ADDRESSBAR_H


addressbar.cpp

#include "addressbar.h"

AddressBar::AddressBar(QWidget *parent) :
QWidget(parent)
{
addressEdit = new QLineEdit(parent);
goButton = new QPushButton("Go", parent);

layout = new QHBoxLayout;
layout->addWidget(addressEdit);
layout->addWidget(goButton);
this->setLayout(layout);

connect(goButton, SIGNAL(clicked()), this, SLOT(goToSite()));
connect(addressEdit, SIGNAL(returnPressed()), this, SLOT(goToSite()));
}

void AddressBar::goToSite()
{
QString address = addressEdit->text();
emit go(QUrl(address));
}


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

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);
}


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

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"

class MainWindow : public QMainWindow
{
Q_OBJECT

public:
explicit MainWindow(QWidget *parent = 0);

};

#endif // MAINWINDOW_H


mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent)
{
// 1.Create widget
QWidget *centralWidget = new QWidget(this);
AddressBar *bar = new AddressBar;
HtmlView *view = new HtmlView;

// 2.Add widget to layout
QGridLayout *layout = new QGridLayout;
layout->addWidget(bar, 0, 0, 1, 10);
layout->addWidget(view, 1, 0, 1, 10);
centralWidget->setLayout(layout);

// 3.Connect widget
QObject::connect(bar, SIGNAL(go(QUrl)), view, SLOT(loadNewPage(QUrl)));

this->setCentralWidget(centralWidget);
this->setWindowTitle("My Browser v1.0");
this->resize(640, 480);
}


最后是程序的入口main.cpp

#include <QApplication>
#include "mainwindow.h"

int main(int argc, char *argv[])
{
QApplication app(argc, argv);

MainWindow *window = new MainWindow;
window->show();

return app.exec();
}


2.事件流分析



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

这里需要注意的是SIGNAL-SLOT机制是Qt的内部机制,它是同步执行的。源头上returnPressed()和clicked()槽的触发,
是从操作系统的事件队列中得到的,并进行异步的处理。以QPushButton的clicked()槽的触发为例,QApplication.exec()
执行后将会监听操作系统事件队列,当鼠标事件发生时,事件将会发送到QPushButton的event()函数进行分发:

QPushButton::event ->
QAbstractButton::event ->
QWidget::event [Dispatch event]:
case QEvent::KeyPress: {
QKeyEvent *k = (QKeyEvent *)event;
bool res = false;
if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) {  //### Add MetaModifier?
if (k->key() == Qt::Key_Backtab
|| (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier)))
res = focusNextPrevChild(false);
else if (k->key() == Qt::Key_Tab)
res = focusNextPrevChild(true);
if (res)
break;
}
keyPressEvent(k);

-> QPushButton::keyPressEvent
void QPushButton::keyPressEvent(QKeyEvent *e)
{
Q_D(QPushButton);
switch (e->key()) {
case Qt::Key_Enter:
case Qt::Key_Return:
if (autoDefault() || d->defaultButton) {
click();
break;
}
// fall through
default:
QAbstractButton::keyPressEvent(e);
}
}

-> QAbstractButton::click:
void QAbstractButton::click()
{
if (!isEnabled())
return;
Q_D(QAbstractButton);
QPointer<QAbstractButton> guard(this);
d->down = true;
d->emitPressed();
if (guard) {
d->down = false;
nextCheckState();
if (guard)
d->emitReleased();
if (guard)
d->emitClicked();
}
}


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浏览器项目
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: