哈嘍,我是老吳。
最近又玩了一下 Qt,給大家分享一點(diǎn) Qt 相關(guān)的基礎(chǔ)知識(shí)吧。
我個(gè)人非常喜歡 Qt,它簡(jiǎn)直就是我這個(gè) C++ 手殘黨的利器。
學(xué)習(xí) Qt 的最佳途徑應(yīng)該是閱讀官方的手冊(cè)和示例,今天要分享的就是 Qt 官方提供的一個(gè)示例。
http 下載小工具:

源碼文件:
Makefile
httpwindow.cpp
main.cpp
httpwindow.h
http.pro下面快速地說(shuō)明一下如何實(shí)現(xiàn)這個(gè)小工具, let's go.
目錄:
1.?實(shí)現(xiàn)主界面
2.?解析?URL?和創(chuàng)建空文件
3.?發(fā)送?http?請(qǐng)求和接收?http?數(shù)據(jù)
4.?添加進(jìn)度條
5.?下載完成后自動(dòng)打開(kāi)文件1. 實(shí)現(xiàn)主界面
主界面基于 QDialog,包括:
- 3 個(gè) LineEdit;
- 1 個(gè) CheckBox;
- 1 個(gè) Label;
- 2 個(gè) Button;
代碼如下:
httpwindow.h
class?HttpWindow?:?public?QDialog
{
????...
}httpwindow.cpp
HttpWindow::HttpWindow(QWidget?*parent)
????:?QDialog(parent)
????...{
????QFormLayout?*formLayout?=?new?QFormLayout;
????formLayout->addRow(tr("&URL:"),?urlLineEdit);
????formLayout->addRow(tr("&Download?directory:"),?downloadDirectoryLineEdit);
????formLayout->addRow(tr("Default?&file:"),?defaultFileLineEdit);
????formLayout->addRow(launchCheckBox);
????
????QVBoxLayout?*mainLayout?=?new?QVBoxLayout(this);
????mainLayout->addLayout(formLayout);
????mainLayout->addWidget(statusLabel);
????QPushButton?*quitButton?=?new?QPushButton(tr("Quit"));
????QWidget::close);
????QDialogButtonBox?*buttonBox?=?new?QDialogButtonBox;
????buttonBox->addButton(downloadButton,?QDialogButtonBox::ActionRole);
????buttonBox->addButton(quitButton,?QDialogButtonBox::RejectRole);
????mainLayout->addWidget(buttonBox);
}用 QFormLayout 對(duì) 3 個(gè)編輯框進(jìn)行表單布局,然后再Q(mào)VBoxLayout 來(lái)進(jìn)行整體的垂直布局。
main.cpp:
int?main(int?argc,?char?*argv[]){
????...
????HttpWindow?httpWin;
????httpWin.show();
????...
}運(yùn)行效果:

此時(shí)只有界面, Download 按鍵并沒(méi)有實(shí)際的功能。
2. 解析 URL 和創(chuàng)建空文件
當(dāng)用戶點(diǎn)擊 Downaload 按鍵時(shí),需要解析用戶輸入的 URL 并打開(kāi)一個(gè)新文件用于保存將要下載的文件。
代碼如下:
1. 為 Download 按鍵綁定槽
connect(downloadButton,?&QAbstractButton::clicked,?this,?&HttpWindow::downloadFile);
}2. 解析 URL
void?HttpWindow::downloadFile(){????
????//?獲得?URL
????const?QString?urlSpec?=?urlLineEdit->text().trimmed();
????const?QUrl?newUrl?=?QUrl::fromUserInput(urlSpec);
????//?獲得?文件保存路徑
????QString?fileName?=?newUrl.fileName();
????QString?downloadDirectory?=?QDir::cleanPath(downloadDirectoryLineEdit->text().trimmed());
????fileName.prepend(downloadDirectory?+?'/');
}從 URL 中提取出文件名,和下載路徑拼接在一起形成完整的文件路徑。
3. 創(chuàng)建空文件
void?HttpWindow::downloadFile(){
????...
????if?(QFile::exists(fileName))?{
????????QFile::remove((fileName));
????}
????file?=?openFileForWrite(fileName);
????...
}
std::unique_ptr<QFile>?HttpWindow::openFileForWrite(const?QString?&fileName){
????std::unique_ptr<QFile>?file(new?QFile(fileName));
????file->open(QIODevice::WriteOnly);
????
????return?file;
}運(yùn)行效果:

3. 發(fā)送 http 請(qǐng)求和接收 http 數(shù)據(jù)
在 Qt 里,可以用 QNetworkAccessManager 發(fā)送 http request,用 QNetworkReply 保存 http reply。
class?HttpWindow?:?public?QDialog
{
private:
????...
????QUrl?url;
????QNetworkAccessManager?qnam;
????QNetworkReply?*reply;
};當(dāng)用戶按下 Download 鍵時(shí),發(fā)送 http request:
void?HttpWindow::startRequest(const?QUrl?&requestedUrl){
????url?=?requestedUrl;
????reply?=?qnam.get(QNetworkRequest(url));
????connect(reply,?&QIODevice::readyRead,?this,?&HttpWindow::httpReadyRead);
????connect(reply,?&QNetworkReply::finished,?this,?&HttpWindow::httpFinished);
????statusLabel->setText(tr("Downloading?%1...").arg(url.toString()));
}當(dāng)有數(shù)據(jù)到來(lái)時(shí),將其寫到文件中:
void?HttpWindow::httpReadyRead(){
????if?(file)
????????file->write(reply->readAll());
}當(dāng)數(shù)據(jù)傳輸完畢后,提示用戶下載完畢:
void?HttpWindow::httpFinished(){
????QFileInfo?fi;
????if?(file)?{
????????fi.setFile(file->fileName());
????????file->close();
????????file.reset();
????}
????statusLabel->setText(tr("Downloaded?%1?bytes?to?%2\nin\n%3")
?????????????????????????.arg(fi.size()).arg(fi.fileName(),?QDir::toNativeSeparators(fi.absolutePath())));
????downloadButton->setEnabled(true);
}運(yùn)行效果:

4. 添加進(jìn)度條
發(fā)送請(qǐng)求后,創(chuàng)建一個(gè)進(jìn)度條。
進(jìn)度條的百分比和 http reply 的數(shù)據(jù)綁定在一起:
void?HttpWindow::startRequest(const?QUrl?&requestedUrl){
????...
????ProgressDialog?*progressDialog?=?new?ProgressDialog(url,?nullptr);
????...
????connect(reply,?&QNetworkReply::downloadProgress,?progressDialog,?&ProgressDialog::networkReplyProgress);
????...
????progressDialog->show();
}
//?更新進(jìn)度條的百分比
void?ProgressDialog::networkReplyProgress(qint64?bytesRead,?qint64?totalBytes){
????setMaximum(totalBytes);
????setValue(bytesRead);
}運(yùn)行效果:

5. 下載完成后自動(dòng)打開(kāi)文件
QDesktopServices 用于訪問(wèn)常見(jiàn)的桌面服務(wù)。
許多桌面環(huán)境都會(huì)提供一系列服務(wù),可以通過(guò)應(yīng)用程序來(lái)執(zhí)行常見(jiàn)任務(wù)。例如以用戶應(yīng)用程序首選項(xiàng)的方式打開(kāi)一個(gè)網(wǎng)頁(yè)或者 PDF。
當(dāng)下載完畢后,如果用戶使能了 Launch file 選項(xiàng),則打開(kāi)此下載文件:
void?HttpWindow::httpFinished(){
????...
????if?(launchCheckBox->isChecked())?{?
????????QDesktopServices::openUrl(QUrl::fromLocalFile(fi.absoluteFilePath()));
????}
????downloadButton->setEnabled(true);
}運(yùn)行效果:

到此,這個(gè) http 下載小工具就實(shí)現(xiàn)完畢啦。
嘿嘿,你們會(huì)學(xué)會(huì)了嗎?
相關(guān)參考
https://doc.qt.io/qt-5/qtnetwork-http-example.html
思考技術(shù),也思考人生
要學(xué)習(xí)技術(shù),更要學(xué)習(xí)如何生活。
好書推薦:
《指數(shù)基金投資指南》
作者銀行螺絲釘,專注于低估值指數(shù)基金投資,系統(tǒng)性地講解各類指數(shù)基金,以及投資指數(shù)基金的有效策略。

能收獲什么?
- 溫習(xí)了一些關(guān)于基金定投的基礎(chǔ)知識(shí);
你和我各有一個(gè)蘋果,如果我們交換蘋果的話,我們還是只有一個(gè)蘋果。但當(dāng)你和我各有一個(gè)想法,我們交換想法的話,我們就都有兩個(gè)想法了。
覺(jué)得文章對(duì)你有價(jià)值,不妨 在看 + 分享。
推薦閱讀: