用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. JQuery属性过滤(转)

    属性过滤(Attribute Filters)的内容就是html元素中的属性 其包括以下几个选择器: [attribute] [attribute=value] [attribute!=value] ...

  2. (五)unity4.6Ugui中文教程文档-------概要-UGUI Interaction Components

    watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxMDAxOTcxNw==/font/5a6L5L2T/fontsize/400/fill/I0JBQk ...

  3. (2)入门指南——(2)jQuery可以做什么(What jQuery does)

    The jQuery library provides a general-purpose abstraction layer for common web scripting, and is, th ...

  4. [转] 为什么医疗咨询服务公司Evolent Health仅用4年就华丽上市?

    让医疗主体,即医院和医生担任保险角色,完全控制保费,实现医疗机构的利益最大化.美国公司EvolentHealth帮助所有医院实现这一梦想. 不觉间,已步入2015的下半年.当国内还在讨论商业保险何时能 ...

  5. 使用solr报错,错误信息 include(SolrClient.php): failed to open stream: No such file or directory

    这个是因为本地没有安装php-solr的扩展导致的,安装方法(使用的是ubuntu) cd /optwget http://pecl.php.net/get/solr-1.0.2.tgztar -xv ...

  6. Creating LVM Logical Volumes

    LVM-Logical Volume Manager逻辑卷管理的一些基本概念: 用途: 在零停机前提下可以自如对文件系统的大小进行调整,可以方便实现文件系统跨越不同磁盘和分区.当系统添加了新的磁盘,通 ...

  7. java06switch

    public class SwitchTest { public static void main(String[] args) { /** * 如果第一名,参加麻省理工大学组织的1个月夏令营 * 如 ...

  8. wininet API调用,检测网络

    [DllImport("wininet")]        private extern static bool InternetGetConnectedState(out int ...

  9. JDBC数据源连接池的配置和使用实例

    个人学习参考所用,勿喷! 使用JDBC建立数据库连接的两种方式: 1.在代码中使用DriverManager获得数据库连接.这种方式效率低,并且其性能.可靠性和稳定性随着用户访问量得增加逐渐下降. 2 ...

  10. Java内存分配和GC

    Java内存分配和回收的机制概括的说,就是:分代分配,分代回收. 对象将根据存活的时间被分为:年轻代(Young Generation).年老代(Old Generation).永久代(Permane ...