用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浏览器项目

用QtWebKit开发简单的浏览器的更多相关文章

  1. iOS开发UI篇—简单的浏览器查看程序

    iOS开发UI篇—简单的浏览器查看程序 一.程序实现要求 1.要求 2. 界面分析 (1) 需要读取或修改属性的控件需要设置属性 序号标签 图片 图片描述 左边按钮 右边按钮 (2) 需要监听响应事件 ...

  2. Django开发简单采集用户浏览器信息的小功能

    Django开发简单采集用户浏览器信息的小功能 Centos环境准备 yum install –y python-pip export http_proxy=http://10.11.0.148:80 ...

  3. 基于.net开发chrome核心浏览器【七】

    这是一个系列的文章,前面六篇文章的地址如下: 基于.net开发chrome核心浏览器[六] 基于.net开发chrome核心浏览器[五] 基于.net开发chrome核心浏览器[四] 基于.net开发 ...

  4. 分享:用 NDK C++做底层开发的Android 浏览器,纯免费,无广告

    分享:用 NDK C++做底层开发的Android 浏览器,纯免费,无广告 操作简单,傻瓜一看就会 无毒.无广告.无负作用,完全免费 下载地址1:http://awdjcfeizb.l33.yunpa ...

  5. 基于.net开发chrome核心浏览器【五】

    一:本篇将解决的问题 本章主要为了解决一下几个问题: 1.JsDialog的按钮错位的问题 我们开发出的浏览器,在有些操系统上调用alert,confirm之类的对话框时,确定和取消按钮会出现错位的情 ...

  6. Pyqt 一个简单的浏览器

    使用QtWebKit 做一个简单的浏览器. mybrowserUI.ui <?xml version="1.0" encoding="UTF-8"?> ...

  7. 基于.net开发chrome核心浏览器

    本文转载自:http://www.cnblogs.com/liulun/archive/2013/04/20/3031502.html 一: 上一篇的链接: 基于.net开发chrome核心浏览器[一 ...

  8. iOS开展UI一片—简单的浏览器观看节目

    iOS开发UI篇-简单的浏览器查看程序 一.程序实现要求 1.要求 2. 界面分析 (1) 须要读取或改动属性的控件须要设置属性 序号标签 图片 图片描写叙述 左边button 右边button (2 ...

  9. 基于.net开发chrome核心浏览器【四】

    原文:基于.net开发chrome核心浏览器[四] 一: 上周去北京出差,给国家电网的项目做架构方案,每天都很晚睡,客户那边的副总也这样拼命工作. 累的不行了,直接导致第四篇文章没有按时发出来. 希望 ...

随机推荐

  1. Ubuntu + Win7 双系统 重装win7后进入不了Ubuntu

    机子上先有win7,然后装Ubuntu,装完Ubuntu后,开机进入Ub开机界面,里面有ubuntu,win7 loader(启动项),选择win7启动后就出现读盘错误. 天,我怎么能修复好这双系统启 ...

  2. JQuery window、document、 body (转)

    转自:http://www.cnblogs.com/luhe/archive/2012/11/08/2760619.html 我电脑屏幕分辨率:1440 * 900   最大化浏览器,刷新浏览器 al ...

  3. Duplicate Protocol Definition of DTService Is Ignored

    1.  很多的情况是由于重复导入Protocol导致的. 例如:import "Protocol1.h" import "Protocol1.h" 在同一项目中 ...

  4. 【转】大素数判断和素因子分解【miller-rabin和Pollard_rho算法】

    集训队有人提到这个算法,就学习一下,如果用到可以直接贴模板,例题:POJ 1811 转自:http://www.cnblogs.com/kuangbin/archive/2012/08/19/2646 ...

  5. Python基础类型

    1. 列表.元组操作 列表是我们最以后最常用的数据类型之一,通过列表可以对数据实现最方便的存储.修改等操作 定义列表 names = ['Alex',"Tenglan",'Eric ...

  6. Vs2010发布Asp.Net网站及挂到IIS服务上

    首先用vs2010打开一个Asp.Net项目, 也可以通过vs菜单->生成->发布网站                           选择发布网站的路径 这样发布就OK了 下面就吧发 ...

  7. HTML5摇一摇

    方式一 (function(){ /** * 摇一摇 * @author rubekid */ function Shake(options){ this.init(options); } Shake ...

  8. Lua 基础知识-面向对象

    通过函数闭包的方式来实现面向对象 -- 通过函数闭包的方式来实现面向对象 function People(name) local self = {} local function init() sel ...

  9. iOS中枚举定义的三种方式

    最简单的方式 typedef enum{ num1 = 0, num2 = 1, num3 = 2 }num; 同时我们还可以使用NS_ENUM的方式定义枚举 typedef NS_ENUM (NSI ...

  10. 【C#学习笔记】二、面向对象编程

    2.1 抽象类与接口 1)概念 抽象类是特殊的类,只是不能被实例化:除此以外,具有类的其他特性:重要的是抽象类可以包括抽象方法,这是普通类所不能的.抽象方法只能声明于抽象类中,且不包含任何实现,派生类 ...