[Qt教程] 第34篇 網絡(四)FTP(二)
樓主
發表於 2013-9-4 15:04:38 | 查看:
315| 回複: 9

FTP(二)
版權聲明
該文章原創於作者yafeilinux,轉載請注明出處!
導語
前麵講述了一個最簡單的FTP客戶端程序的編寫,這一節我們將這個程序進行擴展,使其可以瀏覽並能下載服務器上的所有文件。
環境:Windows Xp + Qt 4.8.5+QtCreator 2.8.0
目錄
一、修改界麵
二、功能實現
正文 一、修改界麵
我們刪除了TextBrowser ,加入了幾個Label ,Line Edit ,Push
Button部件,一個Tree Widget及一個Progress Bar部件。然後我們對其中幾個部件做如下更改。
(1)將“FTP服務器”標簽後的Line Edit的objectName屬性改為“ftpServerLineEdit”,其text 屬性改為“ftp.qt-project.org”。
(2)將“用戶名”標簽後的Line Edit的objectName屬性改為“userNameLineEdit”,其text屬性改為“anonymous”,將其toolTip屬性改為“默認用戶名請使用:anonymous ,此時密碼任意。”
(3)將“密碼”標簽後的Line Edit的objectName屬性改為“passWordLineEdit”,其text屬性改為“123456”,將其echoMode屬性改為“Password”。
(4)將“連接”按鈕的objectName屬性改為“connectButton”。
(5)將“返回上一級目錄”按鈕的objectName屬性改為“cdToParentButton”。
(6)將“下載”按鈕的objectName屬性改為“downloadButton”。
(7)將Tree Widget的objectName屬性改為“fileList”,然後在Tree
Widget部件上單擊鼠標右鍵,選擇Edit Items菜單,添加列屬性如下。
![]() 最終界麵如圖所示:
![]()
下麵我們的程序中,就是實現在用戶填寫完相關信息後,按下“連接”按鈕,就可以連接到FTP服務器,並在TreeWidget中顯示服務器上的所有文件,我們可以按下“下載”按鈕來下載選中的文件,並使用進度條顯示下載進度。
二、功能實現
1.更改widget.h文件。
(1)添加頭文件#include <QtGui>
(2)在private中添加變量:
QHash<QString, bool> isDirectory; //用來存儲一個路徑是否為目錄的信息
QString currentPath; //用來存儲現在的路徑
QFile *file;
(3)添加槽:
private slots:
void on_downloadButton_clicked();
void on_cdToParentButton_clicked();
void on_connectButton_clicked();
void ftpCommandFinished(int,bool);
void ftpCommandStarted(int);
void updateDataTransferProgress(qint64,qint64 );//更新進度條
//將服務器上的文件添加到Tree Widget中
void addToList(const QUrlInfo &urlInfo);
void processItem(QTreeWidgetItem*,int);//雙擊一個目錄時顯示其內容
2.更改widget.cpp的內容。
(1)實現“連接”按鈕的單擊事件槽。
void Widget::on_connectButton_clicked()
//連接按鈕
{
ui->fileList->clear();
currentPath.clear();
isDirectory.clear();
ftp = new QFtp(this);
connect(ftp,SIGNAL(commandStarted(int)),
this,SLOT(ftpCommandStarted(int)));
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);
//登錄
}
我們在“連接”按鈕的單擊事件槽函數中新建了ftp對象,然後關聯了相關的信號和槽。這裏的listInfo()信號由ftp->list()函數發射,它將在登錄命令完成時調用,下麵我們提到。而dataTransferProgress()信號在數據傳輸時自動發射。最後我們從界麵上獲得服務器地址,用戶名和密碼等信息,並以它們為參數執行連接和登錄命令。
(2)更改ftpCommandFinished()函數。
我們在相應位置做更改。
首先,在登錄命令完成時,我們調用list()函數:
ui->label->setText(tr("登錄成功"));
ftp->list();
//發射listInfo()信號,顯示文件列表
然後,在下載命令完成時,我們使下載按鈕可用,並關閉打開的文件。
ui->label->setText(tr("已經完成下載"));
ui->downloadButton->setEnabled(true);
file->close();
delete file;
最後再添加一個if語句,處理list命令完成時的情況:
if (ftp->currentCommand() == QFtp::List){
if (isDirectory.isEmpty())
{ //如果目錄為空,顯示“empty”
ui->fileList->addTopLevelItem(
new QTreeWidgetItem(QStringList()<< tr("<empty>")));
ui->fileList->setEnabled(false);
ui->label->setText(tr("該目錄為空"));
}
}
我們在list命令完成時,判斷文件列表是否為空,如果為空,就讓Tree Widget不可用,並顯示“empty”條目。
(3)添加文件列表函數的內容如下。
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(3, urlInfo.group());
item->setText(4, urlInfo.lastModified().toString("MMM dd yyyy"));
QPixmap pixmap(urlInfo.isDir() ? "../myFtp2/dir.png" : "../myFtp2/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);
}
}
當ftp->list()函數執行時會發射listInfo()信號,此時就會執行addToList()函數,在這裏我們將文件信息顯示在Tree
Widget上,並在isDirectory中存儲該文件的路徑及其是否為目錄的信息。為了使文件與目錄進行區分,我們使用了不同的圖標file.png和dir.png來表示它們,這兩個圖標放在了工程文件夾中。
(4)將構造函數的內容更改如下。
{
ui->setupUi(this);
ui->progressBar->setValue(0);
//鼠標雙擊列表中的目錄時,我們進入該目錄
connect(ui->fileList,SIGNAL(itemActivated(QTreeWidgetItem*,int)),
this,SLOT(processItem(QTreeWidgetItem*,int)));
}
這裏我們隻是讓進度條的值為0,然後關聯了Tree Widget的一個信號itemActivated()。當鼠標雙擊一個條目時,發射該信號,我們在槽函數中判斷該條目是否為目錄,如果是則進入該目錄。
(5)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);
}
}
(6)“返回上一級目錄”按鈕的單擊事件槽函數如下。
void Widget::on_cdToParentButton_clicked() //返回上級目錄按鈕
{
ui->fileList->clear();
isDirectory.clear();
currentPath = currentPath.left(currentPath.lastIndexOf('/'));
if (currentPath.isEmpty()) {
ui->cdToParentButton->setEnabled(false);
ftp->cd("/");
} else {
ftp->cd(currentPath);
}
ftp->list();
}
在返回上一級目錄時,我們取當前路徑的最後一個“/”之前的部分,如果此時路徑為空了,我們就讓“返回上一級目錄”按鈕不可用。
(7)“下載”按鈕單擊事件槽函數如下。
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);
}
在這裏我們獲取了當前項目的文件名,然後新建文件,使用get()命令下載服務器上的文件到我們新建的文件中。
(8)更新進度條函數內容如下。
void Widget::updateDataTransferProgress( //進度條
qint64 readBytes,qint64 totalBytes)
{
ui->progressBar->setMaximum(totalBytes);
ui->progressBar->setValue(readBytes);
}
3.流程說明。
整個程序的流程就和我們實現函數的順序一樣。用戶在界麵上輸入服務器的相關信息,然後我們利用這些信息進行連接並登錄服務器,等登錄服務器成功時,我們列出服務器上所有的文件。對於一個目錄,我們可以進入其中,並返回上一級目錄,我們可以下載文件,並顯示下載的進度。
對於ftp的操作,全部由那些命令和信號來完成,我們隻需要調用相應的命令,並在其發出信號時,進行對應的處理就可以了。而對於文件的顯示,則是視圖部分的知識了。
4.運行程序,效果如下圖所示。
![]() ![]() 結語
最後需要說明的是,因為為了更好的講解知識,使得程序簡單化,所以我們省去了很多細節上的處理,如果需要,你可以自己添加。比如斷開連接和取消下載,你都可以使用
ftp->abort()函數。你也可以參考Qt自帶的Ftp
Example例子。對於其他操作,比如上傳等,你可以根據需要添加。
FTP的相關編程就講到到這裏。
涉及到的源碼下載: ![]() |
最後更新:2017-04-03 14:54:15