一、资源下载地址

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的方式,否则会死机。

Qt开发Gif播放器的更多相关文章

  1. Qt+MPlayer音乐播放器开发笔记(一):ubuntu上编译MPlayer以及Demo演示

    前言   在ubuntu上实现MPlayer播放器播放音乐.   Demo                Mplayer   MPlayer是一款开源多媒体播放器,以GNU通用公共许可证发布.此款软件 ...

  2. Qt 简易图片播放器

    一.前言 使用 Qt 制作了一个简单的图片播放器,点击 "浏览按钮" 浏览图片所在目录,目录中的所有图片缩小图标和名称会显示在左侧的图片列表中,点击列表中的图片项,可以在右侧区域的 ...

  3. android开发音乐播放器--Genres和Art album的获取

    最近在做一个项目,其中涉及到音乐播放器.当用到Genres和Art album时花费了一些时间才搞定,今天把方法草草列出,以供自己以后忘记时查看,也希望可以帮助碰到同样问题的道友!! 一.Genres ...

  4. gstreamer应用开发(播放器)之旅

    GStreamer开发,主要分为两块:应用开发.插件开发. 插件开发人员,通常是编解码库的作者(做出了编解码库后,希望gstreamer能用起来这个库,因此增加这个适配层).芯片原厂人员(将自家的hw ...

  5. Android本地视频播放器开发--简易播放器原型

    在以前的基础上,将音视频进行合并,音频播放采用OpenSL ES,视频播放采用OpenGL ES2.0进行显示,这次的版本其中音频和视频是在同一个线程,会造成音频断断续续,后续会采用音频使用SDL,视 ...

  6. Qt实现网络播放器

        写了这么多的博客,关于网络的还不算多,经常有人询问一些关于网络传输.制作在线试听及下载音乐.构造及解析数据等的一些问题,今天就在这里一并讲解.   网络操作:     主要涉及:QNetwor ...

  7. 网页播放音频、视频文件——基于web的html 5的音乐播放器(转载)

    文章转载自:开源中国社区 [http://www.oschina.net] 想通过手机客户端(支持 Android.iPhone 和 Windows Phone)访问开源中国:请点这里 HTML5 是 ...

  8. 基于Qt Phonon模块实现音乐播放器

    这次使用Qt实现的是一个本地音乐播放器,可以播放下载在计算机本地的音乐,提供了添加歌曲,歌曲列表,清空列表的功能.默认歌曲列表循环播放.音乐播放的实现主要依赖的是Qt 的多媒体框架phonon.该音乐 ...

  9. 基于Qt的开源音乐播放器(CZPlayer)

    CZPlayer CZPlayer是基于Qt开发的一款功能强大的音乐播放器,该播放器的论坛地址请点击here,目前CZPlayer已经是第四个版本了,历史版本也分别在我的github上, github ...

随机推荐

  1. Hibernate框架(一)总结介绍

    作为SSH三大框架之一的Hibernate,是用来把程序的Dao层和数据库打交道用的,它封装了JDBC的步骤,是我们对数据库的操作更加简单,更加快捷.利用Hibernate框架我们就可以不再编写重复的 ...

  2. org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [java.util.List]: Specified class

    错误:org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [java.util ...

  3. JavaScript中使用eval()方法解析json串

    最近在js用到了eval()方法,在这里做个笔记 当时是这么用的:data = eval("("+data+")"); data为后台向前台传送的一个json串 ...

  4. 一道内部ctf文件包含题

    拿到题目 在burp里看下 拿到源码 很明显是一道文件包含题目,包含cookie里的值,于是构造Cookie:language=chinese试试   文件变成中文的了,说明中文语言进行了包含并替换 ...

  5. IP地址与子网化分

    IP地址与子网掩码 一.IP地址的组成 二.IP地址的分类                            1)A.B.C三类地址的组成                            2 ...

  6. PYTHON3.4.4 升级pip

    python -m pip install --upgrade pipupgrade 前面是两个 "-" 

  7. python 子类调用 父类的构造函数

    class A(object): def __init__(self): self.nameaa = 'aa' def funca(self): print('function a %s' % sel ...

  8. DataFrame的创建

    DataFrame的创建从Spark2.0以上版本开始,Spark使用全新的SparkSession接口替代Spark1.6中的SQLContext及HiveContext接口来实现其对数据加载.转换 ...

  9. Luogu2839 [国家集训队]middle 题解

    题目很好,考察对主席树的深入理解与灵活运用. 首先看看一般解决中位数的思路,我们二分一个 \(mid\),将区间中 \(\ge mid\) 的数置为 \(1\),小于的置为 \(-1\),然后求区间和 ...

  10. odoo看板笔记

    案例0001 odoo中看板使用 #其中一定要many2one阶段字段名称 stage_id <kanban default_group_by="stage_id"> ...