一、資源下載地址

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的方式,否則會宕機。