用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. ionic上拉加载更多解决方法

    第一步: $scope.hasmore = true;//是否允许上拉加载 $scope.num = 8;//显示条数 第二步://查询显示内容,查出所有的 $scope.Group = functi ...

  2. HDU 2853 Assignment(KM最大匹配好题)

    HDU 2853 Assignment 题目链接 题意:如今有N个部队和M个任务(M>=N),每一个部队完毕每一个任务有一点的效率,效率越高越好.可是部队已经安排了一定的计划,这时须要我们尽量用 ...

  3. jquery中prop()方法和attr()方法的区别(转)

    jquery1.6中新加了一个方法prop(),一直没用过它,官方解释只有一句话:获取在匹配的元素集中的第一个元素的属性值. 官方例举的例子感觉和attr()差不多,也不知道有什么区别,既然有了pro ...

  4. Resizing LVM Logical Volumes-lvextend

    1. fdisk命令/dev/sdc再分出一个sdc2分区 [root@rhel7 ~]# fdisk /dev/sdc Welcome to fdisk (util-linux ). Changes ...

  5. ios10下,手机连接xcode控制台不显示日志,解决办法

    按照下面设置: run- > environment variables->添加 OS_ACTIVITY_MODE ,value内容为空

  6. 关于飞控下载时候出现avrdude: stk500_getsync(): not in sync: resp=0x00错误的解决方法

    avrdude: stk500_getsync(): not in sync: resp=0x00该问题表述为串口通信失败 经过分析,出现这种情况的原因大致有:1.arduino在IDE下载过程中没有 ...

  7. jdbc02

    分层实现新闻管理系统 1.创建新闻信息实体类,jdbc配置文件以及工具类 public class News { // 新闻信息的实体类 private Integer id; //编号 privat ...

  8. spring01

                                                                       spring的体系结构图 第一个spring入门例子 01.创建一 ...

  9. javascript:void(0)知多少

    在做页面时,如果想做一个链接点击后不做任何事情,或者响应点击而完成其他事情,可以设置其属性 href = "#",但是,这样会有一个问题,就是当页面有滚动条时,点击后会返回到页面顶 ...

  10. Android学习笔记:如何设置ImageView中图片的显示方式

    我们在用ImageView显示图片时,很多情况下图片的大小与ImageView的尺寸不是完全一样的.这时就涉及到该如何设置显示图片了. ImageView有个重要的属性是ScaleType,该属性用以 ...