存档在 ‘GUI开发’ 分类

基于Qt的Http编程-进阶

2011年2月27日

进阶

上文的Http客户端只能下载指定网址的数据,这样的客户端在交互性和功能性上都很差。本文所描述的程序则在这个基本的客户端上进行改造,实现任意目标地址的数据下载,并且改善了用户界面的。具体UI可参考下图:

对于UI而言,该客户端增加了任意地址的输入框、下载进度条和下载按钮;对于下载的数据而言,该客户端不再局限于下载文本数据。接下来本文将按照程序执行的大致顺序对相关函数进行分析。

构造函数

用户界面的设计可见本文参考1和参考2,这里从构造函数开始。在构造函数中除了对用户界面进行初始化外,还创建了一个QNetworkAccessManager对象,并将进度显示条隐藏了起来。

widget::widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::widget)
{
    ui->setupUi(this);
    manager = new QNetworkAccessManager(this);
    ui->progressBar->hide();
}

on_pushButton_clicked槽函数

该槽函数对应着下载按钮的单击事件。该函数完成的工作有从用户界面获得下载地址;从这个地址中解析出所下载文件的名称;打开(创建)所下载的文件;发送下载请求;更新进度显示条的信息。

从上文中可以看到,在Qt中使用QUrl类来存储url地址,通过该类的成员函数还可以根据具体情况对url地址进行相应的处理。使用QFileInfo类的对象存储不依赖具体系统的文件属性,比如文件的名称,路径,访问权限等;通过该类的成员函数可以方便的获取文件的某些属性,比如通过fileName成员函数就可以从路径名中快速解析出文件名。

得到了文件名就可以创建一个QFile类的对象,通过open成员函数就可以打开这个文件,QIODevice::WriteOnly为打开模式。如果打开错误,则弹出警告提示框,并进行相应的错误处理。

文件打开成功后,紧接着就应该发送下载链接的请求了,这个工作将在startRequest()中完成。最后设置进度更新条的初始值,并将其在界面上显示出来。具体的实现代码可参考下图:

void widget::on_pushButton_clicked()
{
    url.setUrl(ui->lineEdit->text());
    QFileInfo info(url.path());//获得地址;
    QString fileName(info.fileName());//从地址中获得文件名;

    //如果地址类似www.edsionte.com,则文件名为index.html;
    if (fileName.isEmpty())
        fileName = "index.html";

    file = new QFile(fileName);
    if (!file->open(QIODevice::WriteOnly))
    {
        QMessageBox::warning(this, tr("Warning"),
                             tr("file open error"),
                             QMessageBox::Yes);
        qDebug() << "file open error";
        delete file;
        file = 0;
        return;
   }
   startRequest(url);//进行请求;
   ui->progressBar->setValue(0);
   ui->progressBar->show();
}

startRequest()的实现

通过参考下面的示例代码就可以发现,该函数注意进行了两部分的内容:发送下载请求并获得数据回复和几组信号和槽函数之间的连接。

get()函数在上文中已有说明,它将返回一个QNetworkReply类的对象reply。当所有的数据下载完毕后,manager对象将发送finished信号,进而调用httpFinished槽函数。

上文所描述的Http客户端是等待所有的数据都下载到内存再读出并显示,而本文所描述的Http客户端则将请求的数据进行分段下载并保存。因此每当有一部分新数据到达本地,reply就会发送readyRead信号,进而调用httpReadyRead槽函数将这部分新的数据保存到本地。使用这种分段下载并保存数据的方法可以有效的节省内存。而一旦网络请求有数据返回,reply对象就会发送downloadProgress信号,进而引发updataReadProcess槽函数对进度显示条进行更新。

void widget::startRequest(QUrl url)
{
    reply = manager->get(QNetworkRequest(url));

    connect(reply, SIGNAL(finished()),
            this, SLOT(httpFinished()));

    connect(reply, SIGNAL(readyRead()),
            this, SLOT(httpReadyRead()));

    connect(reply, SIGNAL(downloadProgress(qint64,qint64)),
            this, SLOT(updataReadProcess(qint64,qint64)));
}

相关槽函数

当有一部分新数据返回到本地后,就回执行httpReadyRead函数。该函数将这部分新到达内存的数据写入file对象所对应的文件中。

void widget::httpReadyRead()
{
    //如果文件存在,则将数据写入文件;
    if (file)
        file->write(reply->readAll());
}

每当请求的数据有返回时,就执行updataReadProcess函数以便及时更新进度显示条。该函数包含两个参数byteRead和totalBytes。前者表示当前接受到的数据总量,后者表示应该下载的数据总量。显然,随着byteRead的增加,进度显示条也不断更新。当byteRead和totalBytes相等时,表示下载完毕。

void widget::updataReadProcess(qint64 byteRead, qint64 totalBytes)
{
    ui->progressBar->setMaximum(totalBytes);//最大值;
    ui->progressBar->setValue(byteRead);//当前值
}

当所有数据都下载完毕后,就执行httpFinished函数。在该函数中将隐藏进度显示条,并将缓冲区的数据清空。并且关闭文件对象,再释放之前申请的一些数据空间。

void widget::httpFinished()
{
    ui->progressBar->hide();
    file->flush();
    file->close();
    reply->deleteLater();
    reply = 0;
    delete file;
    file = 0;
}

至此,基本上完成了一个Http下载客户端。理论上可以下载任何数据,不过我在测试中发现有些地址不能如期下载(比如QQ的下载链接)。

参考:

1. Qt Assistant

2. http://www.yafeilinux.com/?p=734

3. C++ GUI Qt 4编程(第二版); 电子工业出版社;Blanchette,J,Summerfield,M 著;闫锋欣 等译;

基于Qt的Http编程-基本原理

2011年2月26日

在Qt中,使用QNetworkAccessManager类就可以完成基于Http协议的数据上传和下载,该类既可以发送网络请求,也可以接收网络回复。而具体的网络请求是通过QNetworkRequest类发送的,具体的网络回复是通过QNetworkReply类来接收的。

本文将利用上面的几个类实现一个简单的Http客户端,从指定的网址下载数据。

基本原理

由于QNetworkAccessManager类中包含了一组标准的数据请求函数,因此可以通过该类的对象发送数据请求函数;每个请求函数执行完毕时都回返回一个QNetworkReply对象。当所有请求的数据都到达本地后,将引发一个finished()信号,该信号关联了一个处理返回数据的槽函数。具体的实现可参考下述代码:

Widget::Widget(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::Widget)
{
    ui->setupUi(this);

    manager = new QNetworkAccessManager(this);
    connect(manager, SIGNAL(finished(QNetworkReply *)),
            this, SLOT(replyFinished(QNetworkReply*)));

    manager->get(QNetworkRequest(QUrl(
            "http://www.kerneltravel.net/")));
}

可以看到,上述的基本原理大部分都在构造函数中完成。首先创建了一个QNetworkAccessManager对象manager;接着将manager所引发的finished()信号与replyFinished()槽进行关联;最后通过get()发送数据请求。

get()用于发送请求并获得目标地址中的数据,具体的数据请求则是通过创建一个QNetworkRequest类的对象而完成的。只要数据请求发送成功,则开始下载数据。当所有的数据下载完成后,就返回一个QNetworkReply类型的对象。同时manager对象将发送一个finished()信号,引发replyFinished槽函数的执行。

当执行上述的槽函数时,就说明目标地址的数据已经下载完毕。此时槽函数要做的就是将这些数据显示出来。这里我们只只对文本数据进行转换。对这些数据的转换动作可参考下述的代码:

void Widget::replyFinished(QNetworkReply *reply)
{
    QTextCodec *codec = QTextCodec::codecForName("utf8");

    QString all = codec->toUnicode(reply->readAll());
    ui->textEdit->setText(all);
    reply->deleteLater();
}

为了能够正确显示中文,我们创建QTextCodec对象。利用readAll函数可以读取数据请求返回的所有数据,并且利用toUnicode函数将这些数据转换成QString类型。最后在用户界面中的文本编辑器中显示出来。

按照上面的方法就可以下载指定地址的数据。如下图:

当返回的数据显示完毕后,利用deleteLater函数将返回的数据删除。

上述的执行过程用数据流图表示如下:

上述内容只是对基于Http协议的数据下载做了简单的描述,并没有对界面设计作过多的介绍,关于界面的设计可见参考1。下文将对这个基本的Http客户端进行改造。

参考:

1. Qt Assistant

2. http://www.yafeilinux.com/?p=734

3. C++ GUI Qt 4编程(第二版); 电子工业出版社;Blanchette,J,Summerfield,M 著;闫锋欣 等译;

基于Qt4的GUI开发流程

2011年2月19日

最近在学习使用Qt4进行GUI的开发。经过几天的学习,基本上清楚了大致的开发流程。本文以一个简单的文本编辑器为例,说明Qt4的基本开发流程。

之所以选用文本编辑器为例是因为它属于一个标准的主窗口,整个用户界面包含菜单、工具栏、状态栏以及应用程序所需要的对话框。效果图如下:

类似这样的主窗口实现需要三个步骤:用户界面的设计、建立信号与槽之间的连接和自定义槽的实现。Qt4为开发人员提供了两种实现用户界面的方法,一种是通过传统的编码方式实现用户界面;另一种是通过Qt designer(现被集成到Qt Creator中)快速实现。这两种实现方式只是体现在用户界面的设计上,虽然在后续的两个步骤中稍有不同,但本质上是相同的。为了方便说明,本文将这两种设计方式分开描述。

1. 使用编码方式实现

此部分所描述的文本编辑器对应的工程文件为code_myTextEdit,该文本编辑器对应的类为MainWindow,它继承了QMainWindow类。该工程内部所有的文件构成如下图:

1.1 用户界面的实现

如果使用编码方式,则需要在定义MainWindow类的时候声明用户界面所需要的所有部件。比如该文本编辑器的有三个菜单,则需要分别声明三个QMenu类型的变量:menu_File、menu_Edit和menu_Help。此外,还需要声明一些QAction类型的变量,该类型的变量代表鼠标点击菜单或工具栏上相应选项时所产生的动作。比如File菜单中的New选项就对应QAction类型的变量newAct。除上述的成员变量外,在类的定义中还必须声明所需的槽函数。以上这些声明通常被单独放在一个头文件中,即mainwindow.h。

声明完毕后,对用户界面的建立常常会被安排在对应类的构造函数中。其实现通常在.cpp文件中完成,比如mainwindow.cpp。比如在MainWindow类的构造函数中就有createMenus()、createActions()、createToolBars()和createStatusBar()几个函数,他们分别创建主窗口的菜单、菜单选项、工具栏和状态栏。

1.2 建立信号和槽之间的连接

第一部分的代码实现了用户界面,接下来应该建立信号和槽之间的连接。Qt中的信号和槽机制与Java中的事件驱动机制类似,这里的信号相当于用户所引发的事件,而槽本质上就是一个函数,它实现了这个动作所对应的功能。

Qt中使用connect函数来建立信号和槽之间的链接。通常一个信号可以链接多个槽,多个信号也可以链接同一个槽,并且一个信号还可以与另一个信号相连接。连接函数通常放在相关类的构造函数中完成,上述的文本编辑器所对应的MainWindow类的构造函数中,createActions()不仅创建了相应事件的动作对象,而且完成了所有可能引发的事件与相应槽之间的连接。下面是New菜单选项的创建代码:

    newAct = new QAction(tr("&New"), this);
    newAct->setShortcuts(QKeySequence::New);
    newAct->setStatusTip(tr("Create a new file"));
    connect(newAct, SIGNAL(triggered()), this, SLOT(newFile()));

connect函数说明当用户对New选项发出“触发”动作时,当前的对象就调用newFile函数进行事件处理。这里的触发即包含鼠标点击又包含快捷键等。

1.3 实现自定义的槽函数

这部分应该是最关键的一步,根据每个事件的具体功能实现相应的槽函数。比如下面的代码就是实现New菜单选项:

void MainWindow::newFile()
{
    if (maybeSave()) {
        textEdit->clear();
        setCurrentFile("");
    }
}

其中maybeSave()用来判断当前已修改的文件是否进行了保存;如果已保存则清空当前的文本编辑器,并设置相应的主窗口的标题名。其中,maybeSave()和setCurrentFile()都需要用户自己实现。

将第一步声明的所有槽函数都实现后,文本编辑器也基本上算开发完成。

2. 使用设计方式实现

2.1 用户界面的实现

相比传统的编码方式,使用Qt designer则可以快速设计出所需要的用户界面。通过从工具栏中拖动相应的部件到主窗口就可以完成用户界面的涉及。关于主窗口的设计可以参考Qt在线手册中的Creating Main Windows in Qt Designer一节,这里不再赘述。此部分所说的文本编辑器对应的工程文件为design_myTextEdit,内部文件如下图:

如果使用这种可视化的设计方式,则会使用.ui文件保存这个用户界面。用户界面编译器(user interface compiler,uic)则会将.ui文件转换成适合C++的.h文件。比如上述的文本编辑器的用户界面存储在mainwindow.ui中,uic会将其转换成ui_mainwindow.h文件。所生成的ui_mainwindow.h文件中包含了类Ui::MainWindow的定义,该类是一个与mainwindow.ui等价的C++文件。这个类中声明了用户界面中的一些部件以及初始化窗体的setupUi()。

具体在使用时,则通常再定义一个新的类MainWindow,让这个类继承QMainWindow和Ui::MainWindow两个类。此时,就不需要MainWindow中声明窗体中的各个部件了,因为这已经在mainwindow.ui文件中完成;同时对窗体的初始化也可以通过调用setupUi(this)自动完成。这一点是与用编码方式实现用户界面所不同的。

2.2 建立信号和槽之间的连接

使用设计方式创建完主窗口后,建立信号和槽之间的连接也十分简单。只需在事件编辑器中选取具体事件和具体的触发动作,并点击右键的go to slot选项即可在mainwindow.h和mainwindow.cpp文件中创建相应槽函数声明。

2.3 实现自定义的槽函数

到此步只需在实现相应的槽函数即可。比如上述save选项对应的槽如下所示,现在只需输入相应的实现代码即可。

void MainWindow::on_action_Save_triggered()
{
    save();
}

因此,从上述内容来看,创建用户界面的这两种方式在本质上是相同的。虽然设计方式简单方便,但是对于初学者最好两种方法都掌握,这样才能理解用户界面的开发方式。

参考:

1. Qt Assistant

2. http://www.yafeilinux.com/?page_id=3

3. C++ GUI Qt 4编程(第二版); 电子工业出版社;Blanchette,J,Summerfield,M 著;闫锋欣 等译;

 

windows 7 ultimate product key

windows 7 ultimate product key

winrar download free

winrar download free

winzip registration code

winzip registration code

winzip free download

winzip free download

winzip activation code

winzip activation code

windows 7 key generator

windows 7 key generator

winzip freeware

winzip freeware

winzip free download full version

winzip free download full version

free winrar download

free winrar download

free winrar

free winrar

windows 7 crack

windows 7 crack

windows xp product key

windows xp product key

windows 7 activation crack

windows7 activation crack

free winzip

free winzip

winrar free download

winrar free download

winrar free

winrar free

download winrar free

download winrar free

windows 7 product key

windows 7 product key