CEF浏览器客户端实现下载列表功能
【摘要】 这里实现了拓展浏览器的下载功能,实现一个可视化的下载列表,可以控制下载、暂停、删除、打开文件位置、打开文件等功能。
背景
之前的文章已经实现了浏览器的一些扩展功能,如网页的前进、后退、浏览器的刷新、通过组合快捷键调出控制台窗口、设置cookie等。
这里实现了拓展浏览器的下载功能,实现一个可视化的下载列表,可以控制下载、暂停、删除、打开文件位置、打开文件等功能。
效果图
功能
- 暂停下载: 点击暂停按钮,下载暂停。
- 继续下载: 点击继续按钮,下载继续。
- 删除下载: 点击删除按钮,删除下载的本地文件。
- 更新下载进度: 通过进图条展示下载进度。
- 打开文件: 打开下载的本地文件。
- 打开文件夹: 打开下载的本地文件所在的文件夹,并选中文件。
具体实现
首先要修改SimpleHandler类,让SimpleHandler继承CefDownloadHandler类,并重新实现OnBeforeDownload方法和OnDownloadUpdated方法。
//simple_handler.h
class SimpleHandler : public QObject,
public CefClient,
public CefDisplayHandler,
public CefLifeSpanHandler,
public CefLoadHandler,
public CefDownloadHandler //继承CefDownloadHandler类
{
……
virtual CefRefPtr<CefDownloadHandler> GetDownloadHandler() OVERRIDE{return this;} //一定要有
……
// CefDownloadHandler methods:
// 重载OnBeforeDownload和OnDownloadUpdated
virtual void OnBeforeDownload(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDownloadItem> download_item,
const CefString &suggested_name,
CefRefPtr<CefBeforeDownloadCallback> callback) override;
virtual void OnDownloadUpdated(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDownloadItem> download_item,
CefRefPtr<CefDownloadItemCallback> callback) override;
……
}
实现OnBeforeDownload方法:
在正式开始下载前会执行OnBeforeDownload方法,在方法中调用callback的Continue,才算执行了下载命令。参数一是下载时文件的建议名称,参数二是下载时是否弹出路径选择窗口,true表示弹出,false表示不弹出。
void ClientHandler::OnBeforeDownload(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDownloadItem> download_item,
const CefString &suggested_name,
CefRefPtr<CefBeforeDownloadCallback> callback)
{
callback->Continue(suggested_name, true);
}
实现OnDownloadUpdated方法:
OnDownloadUpdated方法中,我们可以通过download_item参数获取是否完成、是否取消、当前速度、完成度百分比、总大小、已完成大小、开始时间、结束时间、路径、建议名称等信息。通过callback参数实现下载的暂停、取消和继续功能。
void ClientHandler::OnDownloadUpdated(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDownloadItem> download_item,
CefRefPtr<CefDownloadItemCallback> callback)
{
int64 bytes = download_item->GetCurrentSpeed(); // 下载速度
int64 totalBytes = download_item->GetTotalBytes(); // 总大小
int64 reciveBytes = download_item->GetReceivedBytes(); // 完成大小
int32 id = download_item->GetId(); // id
QString fileName = QString::fromStdWString(download_item->GetSuggestedFileName());//建议名称
QString url = QString::fromStdString(download_item->GetURL()); //url
QString fullPath = download_item->GetFullPath(); // 本地路径
// 插入一条下载
...
// 更新下载进度
...
// 判断是否下载完成
...
// 取消一条下载
...
}
踩过的坑:
- 在正式开始下载前也会执行OnDownloadUpdated方法,甚至OnDownloadUpdated方法是在OnBeforeDownload方法之前执行的。在下载过程中会不断执行OnDownloadUpdated方法。
- 其中有一个IsInProgress()用来获取是否正在下载。但是我试过,弹出保存框还没有点击保存时,它就返回true。所以不能用它判断是否正在下载过程中。
- 通过download_item获取建议名称时,有些情况会返回空。
最有意思的是:
- 当我们点击下载后,会先执行OnDownloadUpdated,然后执行OnBeforeDownload,此时会弹出弹窗Save file。
- 当我们不管是点击保存还是取消,都会执行若干次OnDownloadUpdated方法,并且每次都可以获取到下载速度、总大小和已完成大小,即使点击了取消,下载速度等值也是有数据的。
- 在若干次OnDownloadUpdated执行完之后,如果我们之前点击的是取消,download_item->IsCanceled()会返回true。如果我们之前点击的是保存,download_item->IsComplete()会返回true。所以我们没有办法在开始下载前判断是否点击了取消按钮。
解决办法:
- 当下载速度大于0时,认定它是一次下载,保存它的id和callback。id作为一条下载的唯一标识。(我当初想用download_item作为一条下载的唯一标识,发现同一条下载的download_item值是会变的。)
- 获取建议名称为空时,通过GetURL()方法获取它的url值,截取url的最后一个反斜杠‘/’后面的字符串作为文件名称。
- 创建一条下载时:将它的id、callback、文件名、总大小通过信号的方式发送给页面。
- 更新下载进度时:通过id作为唯一标识,将下载的当前速度、已下载大小或者百分比通过信号的方式发送给页面。
- 判断是否下载完成:下载完成后才会返回文件下载到本地的路径,通过download_item->GetFullPath()获取。将文件的本地路径通过信号的方式发送给页面。
- 判断是否取消下载:发送取消下载信号给页面。在页面中添加一个标志位,判断接收到的取消信号是我们点击保存框的取消按钮发送的,还是我们在下载过程中点击删除按钮发送的。如果是我们点击保存框的取消按钮时发送的,我们就要将创建的这条下载删除掉。如果是我们在下载过程中点击删除按钮时执行了callback->Cancel()触发的,就不需要删除这一条下载(因为效果图上没有删除)。
- 因为我们在创建一条下载时将callback传递给页面了,所以点击页面上的按钮时,直接调用对应的callback的方法就可以实现暂停、继续、取消了。
- 删除下载就是手动调用callback的取消,如果是删除已经下载完成的,需要将文件从本地删除掉。
删除文件:
QFileInfo fileInfo(filePath);
if(fileInfo.exists())
{
QFile file(m_filePath);
file.remove();
}
打开文件:
QFileInfo fileInfo(filePath);
if(fileInfo.exists())
{
QUrl url = QUrl::fromLocalFile("file:///" + filePath);
QDesktopServices::openUrl(url);
}
打开文件夹并选中文件:
QProcess *m_processFolder; // 打开文件夹进程
m_processFolder = new QProcess(this);
filePath.replace("/", "\"); // 只能识别 "\"
QString cmd = QString("explorer.exe /select,%1").arg(filePath);
m_processFolder->start(cmd);
【版权声明】本文为华为云社区用户原创内容,未经允许不得转载,如需转载请自行联系原作者进行授权。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱:
cloudbbs@huaweicloud.com
- 点赞
- 收藏
- 关注作者
评论(0)