在Qt中,与文件传输协议(FTP)相对应的类为QFtp。在这个类中,提供了许多与文件上传和下载有关的方法,这使得文件的上传与下载变得十分方便。本文所描述的FTP客户端的基本使用方法是:首先输入正确的FTP服务器地址,用户名以及密码;登录成功后将显示服务器中的文件列表;点击下载按钮对某个文件进行下载。用户界面可参考下图:
用户界面设计可见本文参考1和参考2,接下来将对具体的实现过程进行分析。
构造函数
在构造函数中,对用户界面进行了初始化,并隐藏了进度显示条。除此之外,还将itemActivated信号和processItem槽函数进行了连接。当用户双击(或单击,依据具体OS)TreeWidget中的某一条信息时,QTreeWidget类的对象fileList就会发送itemActivated信号。
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); ui->progressBar->setValue(0); connect(ui->fileList, SIGNAL(itemActivated(QTreeWidgetItem*,int)), this, SLOT(processItem(QTreeWidgetItem*,int))); }
on_connectButton_clicked()的实现
在连接按钮单击事件的槽函数中主要完成了两部分工作:登录FTP服务器以及几个信号和槽函数之间的连接,这几个信号均由FTP对象发出。当FTP命令开始执行时,便发出commandStarted信号;当FTP的命令执行完毕时,便发出commandFinished信号;当使用list命令列表显示目录的内容时候,listInfo信号将发出;最后在数据传输的过程中,会不断的发出dataTransferProgress信号以便更新进度显示条。
由于QFtp类中封装了许多与FTP有关成员函数,因此使用connectToHost成员函数可以登录到FTP服务器,使用login函数可以登录到服务器。
void Widget::on_connectButton_clicked() { ui->fileList->clear(); currentPath.clear(); isDirectory.clear(); ftp = new QFtp(this); connect(ftp, SIGNAL(commandFinished(int,bool)), this, SLOT(ftpCommandFinished(int,bool))); connect(ftp, SIGNAL(listInfo(QUrlInfo)), this, SLOT(addToList(QUrlInfo))); connect(ftp, SIGNAL(dataTransferProgress(qint64,qint64)), this, SLOT(updateDataTransferProgress(qint64,qint64))); QString ftpServer = ui->ftpServerLineEdit->text(); QString userName = ui->userNameLineEdit->text(); QString passWord = ui->passWordLineEdit->text(); ftp->connectToHost(ftpServer, 21);//连接到服务器,默认端口是21; ftp->login(userName, passWord);//登录; }
ftpCommandFinished()的实现
当FTP命令执行完毕后,将执行ftpCommandFinished函数。与本文所描述的命令有ConnectToHost()、Login()、Get()、Close()和List()。通过currentCommand成员函数可以具体得到当前执行完毕命令的id,因此根据不同命令的id在用户界面上显示不同的命令状态。
void Widget::ftpCommandFinished(int, bool error) { if (ftp->currentCommand() == QFtp::ConnectToHost) { if (error) ui->label->setText(tr("connecting error %1").arg(ftp->errorString())); else ui->label->setText(tr("connecting success!")); } if (ftp->currentCommand() == QFtp::Login) { if (error) ui->label->setText(tr("login error").arg(ftp->errorString())); else { ui->label->setText(tr("login success!")); ftp->list(); } } //部分代码省略 }
on_downloadButton_clicked()的实现
当单击下载按钮后,将进入该函数进行相应文件的下载。首先通过fileList对象中的成员函数得到要下载文件的名称,在打开该文件,最后通过get函数获取数据。
void Widget::on_downloadButton_clicked() { QString fileName = ui->fileList->currentItem()->text(0); file = new QFile(fileName); if (!file->open(QIODevice::WriteOnly)) { delete file; return; } ui->downloadButton->setEnabled(false); ftp->get(ui->fileList->currentItem()->text(0), file); }
addToList()的实现
当对FTP服务器上某个目录执行list()命令时,对于list()找到的每一个文件都会发出listInfo()信号。该信号会使得addToList函数执行,以便在treeWidget上增加一条新的文件信息。
因此,该函数首先根据urlInfo参数建立一条新的文件信息,然后再利用addTopLevelItem成员函数将该条新的文件信息加入到treeWidget最顶端。
void Widget::addToList(const QUrlInfo &urlInfo) { QTreeWidgetItem *item = new QTreeWidgetItem; item->setText(0, urlInfo.name()); item->setText(1, QString::number(urlInfo.size())); item->setText(2, urlInfo.owner()); item->setText(4, urlInfo.lastModified().toString("mmm dd yyyy")); QPixmap pixmap(urlInfo.isDir() ? "../dir.png" : "../file.png"); item->setIcon(0, pixmap); isDirectory[urlInfo.name()] = urlInfo.isDir(); //存储该路径是否为目录的信息; ui->fileList->addTopLevelItem(item); if (!ui->fileList->currentItem()) { ui->fileList->setCurrentItem(ui->fileList->topLevelItem(0)); ui->fileList->setEnabled(true); } }
processItem()的实现
当双击文件列表中某一项时候,如果该项所显示的文件为目录,则进入该目录中显示其内部的文件列表。上述的内容即为processItem函数所要完成的工作。
void Widget::processItem(QTreeWidgetItem *item, int) { //打开一个目录; QString name = item->text(0); if (isDirectory.value(name)) { ui->fileList->clear(); isDirectory.clear(); currentPath += '/'; currentPath += name; ftp->cd(name); ftp->list(); ui->cdToParentButton->setEnabled(true); } }
updateDataTransferProgress()的实现
每当FTP服务器端的数据返回时,就引发该函数的执行。该函数的主要工作即更新进度条的显示。
void Widget::updateDataTransferProgress(qint64 readBytes, qint64 totalBytes) { ui->progressBar->setMaximum(totalBytes); ui->progressBar->setValue(readBytes); }
未完待续~
参考:
1. Qt Assistant
2. http://www.yafeilinux.com/?p=757
3. C++ GUI Qt 4编程(第二版); 电子工业出版社;Blanchette,J,Summerfield,M 著;闫锋欣 等译;