热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

用Qt开发简单的浏览器(一)

用Qt开发简单的浏览器(一),Go语言社区,Golang程序员人脉社





1.代码实现



工程目录结构如下:







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

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



addressbar.h


#ifndef ADDRESSBAR_H
#define ADDRESSBAR_H
#include
#include
#include
#include
#include
#include
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
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
#include
#include
#include
#include
#include
#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
#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 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浏览器项目




推荐阅读
author-avatar
汽车之家马甲小宝宝_457
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有