Qt开发Gif播放器
一、资源下载地址
https://www.aliyundrive.com/s/jBU2wBS8poH
本项目路径:项目->免费->Gif播放器(包含整个工程源码,vs2019打开即可编译运行)
二、项目介绍
1、本项目使用Vs2019+Qt库来简易开发一个Gif播放器,Qt项目简易开发环境参考文章:
https://www.cnblogs.com/liangqin/p/15129819.html
本文主要论述功能实现细节。
2、本项目完成的功能如下:
(1)、支持双击Gif文件使用本软件打开进行播放。
(2)、软件支持菜单栏打开文件进行播放。
(3)、支持拖放Gif文件到软件内进行播放。
(4)、软件支持循环播放打开的Gif文件。
(5)、使用左右方向键来切换当前打开文件所在目录的所有图片文件。
(6)、Qt线程的使用。
3、效果展示:
三、项目开始
1、准备工作
搭建一份Qt项目简易开发环境,需要注意的是本项目需要Qt的imageformats库。
2、项目思路
菜单栏打开文件、拖拽文件到软件内、双击文件打开可以认为是要获取当前要播放的文件名以及文件所在目录的所有图片文件名,而左右方向键切换则是要更改当前要播放的文件名。我们可以在用户操作后,使用成员变量记录当前播放的文件名以及一个文件名列表和当前播放文件在列表中的位置。然后开启一个线程来循环获取当前需要播放的文件名来读取文件进行播放。
3、界面设计
使用designer来设计我们的UI,增加一个菜单栏打开按钮和添加一个label来显示图像。最后对我们添加的控件进行布局,让label可以随着窗口缩放来自动缩放。如图所示:
4、当前播放文件名与文件名列表获取实现:
void GuiGifView::changeFileName(QString fileName) { //Qt获取的文件路径分隔符是/,编码是utf8 m_file_name = fileName; m_file_change_flag = 1; } void GuiGifView::setFileName(QString fileName) { changeFileName(fileName); //获取路径 QString fileDir = fileName.left(fileName.lastIndexOf("/") + 1); //获取该路径下的图片文件 QDir dir(fileDir); QStringList nameFilters; nameFilters << "*.gif" << "*.jpg" << "*.png"; QStringList files = dir.entryList(nameFilters, QDir::Files|QDir::Readable, QDir::Name); QList<QString>::Iterator it = files.begin(),itend = files.end(); int i = 0; m_file_list.clear(); for (;it != itend; it++,i++) { QString file = fileDir; file += *it; m_file_list.append(file); if (file == fileName) m_cur_file_idx = i; } return; }
5、菜单栏打开文件槽函数实现:
void GuiGifView::on_m_openFile_button_triggered() { QString filename = QFileDialog::getOpenFileName(); if (filename.toStdString() == "") return; setFileName(filename); return ; }
6、文件拖拽实现:
/*拖放分为拖动(Drag)和放下(Drop)两种操作。数据拖动时会被存储为MIME(Multipurpose- * Internet Mail Extensions)类型,在Qt使用QMimeData类来表示MIME类型数据,并还用 * QDrag类来完成数据的转换,而整个拖放操作都是在几个鼠标事件和拖放事件中完成. */ void GuiGifView::dragEnterEvent(QDragEnterEvent* event)//拖动事件 { //可打开.txt,.h,.cpp文件 if (event->mimeData()->hasUrls()) //数据中是否包含URL event->acceptProposedAction(); //如果是则接受动作 else event->ignore(); } void GuiGifView::dropEvent(QDropEvent* event)//放下事件 { const QMimeData* mineData = event->mimeData();//获取MIME数据 if (mineData->hasUrls()) //如数据中包含URL { QList<QUrl>urlList = mineData->urls(); //获取URL列表 if (urlList.isEmpty()) return; //将其中第一个URL表示为本地文件路径 QString filename = urlList.at(0).toLocalFile(); if (filename.isEmpty()) return; setFileName(filename); } }
7、左右方向键切换文件名实现:
void GuiGifView::keyPressEvent(QKeyEvent *event) { //左右按键切换当前文件目录下的图片 if(event->key() == Qt::Key_Left) { m_cur_file_idx -= 1; if(m_cur_file_idx < 0) m_cur_file_idx = m_file_list.count() - 1; changeFileName(m_file_list.at(m_cur_file_idx)); } else if(event->key() == Qt::Key_Right) { m_cur_file_idx += 1; if(m_cur_file_idx >= m_file_list.count()) m_cur_file_idx = 0; changeFileName(m_file_list.at(m_cur_file_idx)); } }
8、label显示图像接口:
void GuiGifView::LabelShowImg(QImage* img) { if(img != NULL) { ui.m_showImg_label->setPixmap(QPixmap::fromImage(*img)); } }
9、开启一个线程来播放图像:
void GuiGifViewThread::run() { while (1) { //程序退出时终止线程 if(m_gui->isExit()) return ; QString file_name = m_gui->getFileName(); if(file_name.toStdString() == "") { QThread::msleep(40); continue; } QImageReader reader(file_name); reader.setDecideFormatFromContent(true); int nCount = reader.imageCount(); int sleep_time = 40; int sleep_flag = 0; for (int i = 0; i < nCount; ++i) { //程序退出时终止线程 if(m_gui->isExit()) return ; //文件名改变重新读取文件 if(m_gui->fileIsChange()) break ; // 跳到顺序号为i的图像 bool ret = reader.jumpToImage(i); QImage image; if(reader.read(&image)) { //图像缩放为label大小 int labelw = m_gui->getImgLabelW(); int labelh = m_gui->getImgLabelH(); int Owidth = image.width(); int Oheight = image.height(); int Fwidth,Fheight;//缩放后的图片大小 float Mul;//记录图片与label大小的比例,用于缩放图片 if(Owidth*1.0/labelw>=Oheight*1.0/labelh) Mul=Owidth*1.0/labelw; else Mul=Oheight*1.0/labelh; Fwidth=Owidth*1.0/Mul; Fheight=Oheight*1.0/Mul; QImage scaledimg; scaledimg = image.scaled(Fwidth,Fheight,Qt::KeepAspectRatio); //只能使用emit方式操作控件,直接操作控件会死机,这里会等待槽函数结束才继续运行(Qt::BlockingQueuedConnection) emit m_gui->sigLabelShowImg(&scaledimg); if(reader.nextImageDelay() > 0) sleep_time = reader.nextImageDelay(); QThread::msleep(sleep_time); sleep_flag = 1; } } if(sleep_flag == 0) QThread::msleep(sleep_time); } }
10、结束语
上面的代码只是本项目中重要的部分,其余代码可以下载工程后进行查看。需要注意的是开启一个线程来操作界面的时候需要使用emit的方式,否则会死机。