給QT新手的練手項目——基於QT的GIF播放器

  本程序在ubuntu12.0四、Qt5以及win7 64bit、Qt4均測試經過。ubuntu

  最近閒來無事,想本身找幾個Qt的小項目作作,因而就從Qt自帶的演示程序着手。在Qt的自帶example有一個movie的小程序,地址在xxx\QT\Examples\x.x\widgets\movie或/opt/Qt/5.1.0/gcc/examples/widgets/widgets中。這是一個用來播放gif文件的程序,在ubuntu運行界面以下:小程序

  其基本功能有載入文件、暫停、中止、退出、快進,顯示播放速度以及根據窗口挑戰文件大小。windows

  這個播放器已經實現了大多數的功能,可是我在調試過程當中發現它的暫停功能並不能實現,快進快退只能使用QSpinBox很不方便,最好集成到button中去。窗口調整的功能有點費,由於通常咱們都但願窗口適應文件的大小而不是文件根據窗口大小來調整,並且使用這樣的調整會使得圖像失真,很差看。最後內置的movie鍵不是很好看,能夠換一下。如下是最後改進後的界面:緩存

  OK,如今就開始。首先建立一個Qt Gui程序命名爲movie。選擇QWidget並命名爲movieplayer,ui可選可不選,咱們這不選:app

  建立文件後進入movieplayer.h,首先聲明一下要用到的庫文件,這邊一次性把接下來全部要用到的都聲明一下:ide

#include<QWidget>
#include<QMovie>
#include<QLabel>
#include<QSpinBox>
#include<QToolButton>
#include<QSlider>
#include<QHBoxLayout>
#include<QGridLayout>
#include<QVBoxLayout>
#include<QIcon>
#include<QPixmap>
#include<QPushButton>
#include<QFileInfo>
#include<QFileDialog>

  接着構造須要用到的控件,這裏須要用戶顯示的frameLabel和另外兩個QLabel,一個用於顯示播放速度的speedSpinBox,一個顯示進度的frameSlider以及另外幾個button控件。這裏須要強調一下,QToolButton通常用於菜單欄和QToolBar一塊兒使用比較多,而菜單欄button通常是要替換掉圖標的,這也使我剛開始認爲只能使用這個,後來發現使用QPushButton其實也同樣,你們有時間能夠實踐一下~還有我這裏隱藏了一個pause鍵,個人想法是,play和pause在一個位置放置,由於這兩個永遠是交替顯示的,因此放在一塊兒能夠節省空間,也更符合當下的主流設置。另外還有能夠對文件進行基本操做的QMovie。currentMovieDirectory是用來標識文件路徑的,如下是這些文件的聲明:函數

QString currentMovieDirectory;
QLabel *movieLabel;
QMovie *movie;
QToolButton *openButton;
QToolButton *playButton;
QToolButton *pauseButton;
QToolButton *stopButton;
QToolButton *quitButton;
QToolButton *speedPlusButton;
QToolButton *speedMinusButton;
QSpinBox *speedSpinBox;
QSlider *frameSlider;
QLabel *frameLabel;
QLabel *speedLabel;

  QLayout的佈置個人想法frameLabel單獨一個,用一個QGridLayout列出進度和速度空間命名爲controlsLayout,用QGridLayout列出快進播放等空間命名爲buttonsLayout,這一行加上open鍵命名爲buttonsLayoutAll,最後整個佈局用mainLayout。佈局

QGridLayout *controlsLayout;
QHBoxLayout *buttonsLayoutAll;
QGridLayout *buttonsLayout;
QVBoxLayout *mainLayout;

  下面進入movieplayer.cpp文件,首先設置窗口屬性,這裏將窗口的大小設爲500*500:學習

setWindowTitle(tr("Movie"));
resize(500,500);

  設置movie的緩存模式,這裏咱們要求當文件播放一遍後返回從新播放,因此使用CacheAll模式:測試

movie = new QMovie(this);
movie->setCacheMode(QMovie::CacheAll);

  設置movieLabel,這裏咱們設置縮放的方式爲Expanding,這樣能夠按照原來文件的尺寸作出較好的調整,不至於被截取部分:

movieLabel=new QLabel(tr("NO movie loaded"));
movieLabel->setAlignment(Qt::AlignCenter);
movieLabel->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
movieLabel->setBackgroundRole(QPalette::Dark);
movieLabel->setAutoFillBackground(true);

  如下是兩個函數:

currentMovieDirectory="movies";

createControls();
createButtons();

  在createControls中,注意幾個控件的佈局要協調:

void movieplayer::createControls()
{
    frameLabel=new QLabel(tr("Current frame:"));
    frameLabel->setAlignment(Qt::AlignVCenter|Qt::AlignRight);

    frameSlider=new QSlider(Qt::Horizontal);
    frameSlider->setTickInterval(1);

    speedLabel=new QLabel(tr("Speed:"));
    speedLabel->setAlignment(Qt::AlignVCenter|Qt::AlignRight);

    speedSpinBox=new QSpinBox;
    speedSpinBox->setRange(1,500);
    speedSpinBox->setValue(movie->speed());
    speedSpinBox->setSuffix(tr("%"));

    controlsLayout=new QGridLayout;
    controlsLayout->addWidget(frameLabel,1,0);
    controlsLayout->addWidget(frameSlider,1,1,1,3);
    controlsLayout->addWidget(speedLabel,1,4);
    controlsLayout->addWidget(speedSpinBox,1,5);
}

  在cteateButtons以前要把圖標文件xxx.png添加到生成的.pro根目錄中去,而後右擊movie,添加新文件,Qt資源文件,定位到根文件夾,命名爲button,系統會自動生成button.qrc文件。點擊button.qrc文件,在最下角前綴輸入框將「/new/prefix1」改爲「/」,而後點擊添加,添加文件,將幾個png文件選擇添加,此時再點擊button.qrc就會看到png文件已經添加進來。

  而後就是button控件的建立。這裏調用QPixmap將圖片添加到button中,設置控件固定大小爲25*25,setAutoRaise能夠將button的外邊框去除在鼠標滑過該button時會有浮出效果顯示邊框,這個效果比較好看。setToolTip函數可使鼠標放在控件上時提示該控件能夠執行的操做,而後調用信號槽作響應的Open(),Start()等操做。

  值得注意的是,play和pause控件將重疊在同一位置。

void movieplayer::createButtons()
{
    QSize iconSize(25,25);

    QPixmap icon1(":/use_001.png");
    openButton=new QToolButton;
    openButton->setIcon(icon1);
    openButton->setAutoRaise(true);
    openButton->setIconSize(iconSize);
    openButton->setToolTip(tr("Open a file"));
    connect(openButton,SIGNAL(clicked()),this,SLOT(Open()));

    QPixmap icon2(":/use_007.png");
    playButton=new QToolButton;
    playButton->setIcon(icon2);
    playButton->setIconSize(iconSize);
    playButton->setAutoRaise(true);
    playButton->setToolTip(tr("Play"));
    connect(playButton,SIGNAL(clicked()),this,SLOT(Start()));

    QPixmap icon3(":/use_008.png");
    pauseButton=new QToolButton;
    pauseButton->setIcon(icon3);
    pauseButton->setAutoRaise(true);
    pauseButton->setIconSize(iconSize);
    pauseButton->setToolTip(tr("Pause"));
    pauseButton->setVisible(false);
    connect(pauseButton,SIGNAL(clicked()),this,SLOT(Pause()));

    QPixmap icon4(":/use_002.png");
    stopButton=new QToolButton;
    stopButton->setIcon(icon4);
    stopButton->setAutoRaise(true);
    stopButton->setIconSize(iconSize);
    stopButton->setToolTip(tr("Stop"));
    connect(stopButton,SIGNAL(clicked()),this,SLOT(Stop()));

    speedMinusButton=new QToolButton;
    QPixmap icon5(":/use_005.png");
    speedMinusButton->setIcon(icon5);
    speedMinusButton->setAutoRaise(true);
    speedMinusButton->setIconSize(iconSize);
    speedMinusButton->setToolTip(tr("Speed up"));
    connect(speedMinusButton,SIGNAL(clicked()),this,SLOT(SpeedDown()));

    speedPlusButton=new QToolButton;
    QPixmap icon6(":/use_011.png");
    speedPlusButton->setIcon(icon6);
    speedPlusButton->setAutoRaise(true);
    speedPlusButton->setIconSize(iconSize);
    speedPlusButton->setToolTip(tr("Speed down"));
    connect(speedPlusButton,SIGNAL(clicked()),this,SLOT(SpeedUp()));

    buttonsLayout=new QGridLayout;
    buttonsLayout->addWidget(speedMinusButton,0,0);
    buttonsLayout->addWidget(playButton,0,1);
    buttonsLayout->addWidget(pauseButton,0,1);
    buttonsLayout->addWidget(speedPlusButton,0,2);
    buttonsLayout->addWidget(stopButton,0,3);

    buttonsLayoutAll=new QHBoxLayout;
    buttonsLayoutAll->addWidget(openButton);
    buttonsLayoutAll->addStretch();
    buttonsLayoutAll->addLayout(buttonsLayout);
    buttonsLayoutAll->addStretch();
}

  接下來利用layout完成整個佈局,如下是完整的構造函數:

movieplayer::movieplayer(QWidget *parent) :
    QWidget(parent)
{
    setWindowTitle(tr("Movie"));
    resize(500,500);

    movie = new QMovie(this);
    movie->setCacheMode(QMovie::CacheAll);

    movieLabel=new QLabel(tr("NO movie loaded"));
    movieLabel->setAlignment(Qt::AlignCenter);
    movieLabel->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding);
    movieLabel->setBackgroundRole(QPalette::Dark);
    movieLabel->setAutoFillBackground(true);

    currentMovieDirectory="movies";

    createControls();
    createButtons();

    connect(movie,SIGNAL(frameChanged(int)),this,SLOT(updateFrameSlider()));
    connect(movie,SIGNAL(stateChanged(QMovie::MovieState)),this,SLOT(updateButtons()));
    connect(frameSlider,SIGNAL(valueChanged(int)),this,SLOT(goToFrame(int)));
    connect(speedSpinBox,SIGNAL(valueChanged(int)),movie,SLOT(setSpeed(int)));

    mainLayout=new QVBoxLayout;
    mainLayout->addWidget(movieLabel);
    mainLayout->addLayout(controlsLayout);
    mainLayout->addLayout(buttonsLayoutAll);
    setLayout(mainLayout);

    updateFrameSlider();
    updateButtons();
}

  中間的信號槽想必不難理解,最後講調用兩個update函數更新控件狀態。

  接下來先對button控件的槽函數作一下定義,首先是Open(),首先得打開的路徑,QFileInfo(fileName).path()將記錄第一次打開文件的路徑,當打開文件後,movie就開始自動播放:

void movieplayer::openFile(const QString &fileName)
{
    currentMovieDirectory=QFileInfo(fileName).path();

    movie->stop();
    movieLabel->setMovie(movie);
    movie->setFileName(fileName);
    movie->start();
}
void movieplayer::Open()
{
    QString fileName=QFileDialog::getOpenFileName(this,tr("Open a flie"),
                                                  currentMovieDirectory);
    if(!fileName.isEmpty())
    {
        openFile(fileName);

        pauseButton->setVisible(true);
        playButton->setVisible(false);
    }
}

  Pause():

void movieplayer::Pause()
{
    movie->setPaused(true);
    playButton->setEnabled(true);
    pauseButton->setEnabled(false);
    pauseButton->setVisible(false);
    playButton->setVisible(true);
}

  Start():

void movieplayer::Start()
{
    movie->start();
    playButton->setEnabled(false);
    playButton->setVisible(false);
    pauseButton->setEnabled(true);
    pauseButton->setVisible(true);
}

  Stop():

void movieplayer::Stop()
{
    movie->stop();
    playButton->setEnabled(true);
    pauseButton->setEnabled(false);
    pauseButton->setVisible(false);
    playButton->setVisible(true);
}

  SpeedUp()&SpeedDown(),這裏設置Speed的範圍是1—500,每按下一次控件增減的量爲20:

void movieplayer::SpeedUp()
{
    qint32 currentSpeed=movie->speed();
    if(currentSpeed<=480)
    {
        movie->setSpeed(currentSpeed+20);
        speedSpinBox->setValue(currentSpeed+20);
    }
    else
    {
        movie->setSpeed(500);
        speedSpinBox->setValue(500);
    }
}

void movieplayer::SpeedDown()
{
    qint32 currentSpeed=movie->speed();
    if(currentSpeed>20)
    {
        movie->setSpeed(currentSpeed-20);
        speedSpinBox->setValue(currentSpeed-20);
    }
    else
    {
        movie->setSpeed(1);
        speedSpinBox->setValue(1);
    }
}

  這裏還有一點要說明,當接受者爲movie時,槽函數將調用系統函數,這也是QMovie的功能所在。其實這裏的Speed()函數時一樣能夠調用movie->setSpeed(),只是由於關聯控件的考慮纔沒有用。

  下面是槽函數goToFrame,用以關聯frameSlider和movie:

void movieplayer::goToFrame(int frame)
{
    movie->jumpToFrame(frame);
}

  最後是update函數,在updateFrameSlider中,首先設定frameSlider的最大值,若是打開的movie存在,將激活除pause外的全部控件:

void movieplayer::updateFrameSlider()
{
    bool hasFrame=(movie->currentFrameNumber()>=0);

    if(hasFrame)
    {
        if(movie->frameCount()>0)
            frameSlider->setMaximum(movie->frameCount()-1);
        else
        {
            if(movie->currentFrameNumber()>frameSlider->maximum())
                frameSlider->setMaximum(movie->currentFrameNumber());
        }
        frameSlider->setValue(movie->currentFrameNumber());
    }
    else
        frameSlider->setMaximum(0);

    frameLabel->setEnabled(hasFrame);
    frameSlider->setEnabled(hasFrame);
    speedMinusButton->setEnabled(hasFrame);
    speedPlusButton->setEnabled(hasFrame);
    stopButton->setEnabled(hasFrame);
}

  updateButtons的設定是原來程序裏的,這裏沒有作修改0v0:

void movieplayer::updateButtons()
{
    playButton->setEnabled(movie->isValid()&&movie->frameCount()!=1
            &&movie->state()==QMovie::NotRunning);
    pauseButton->setEnabled(movie->state()!=QMovie::NotRunning);
    pauseButton->setCheckable(movie->state()==QMovie::NotRunning);
    stopButton->setEnabled(movie->state()!=QMovie::NotRunning);
}

  通過上述步驟,就能夠獲得開頭所示的gif播放器了,加載了文件以下:

  若是要生成可執行文件,就要將默認的debug改成release,就能夠生成了:

  在windows中每每須要將安裝目錄下/bin中的libgcc_s_dw2-1.dll、mingwm10.dll、QtCore4.dll、QtGui4.dll一併拷入exe所在的目錄,這樣就能夠點擊exe直接執行啦!!

  最後,若是你嫌默認的exe圖標不夠好看,你也能夠將其替換成你喜歡的圖形。這裏須要強調,在以前的button中,圖像文件能夠是png、ico、jpeg等格式的,可是在這裏,系統只接受ico格式的!

  將可執行文件替換成本身想要的圖標須要如下幾個步驟:

  一、將你的ico文件放入根目錄,我用的是i.icon;

  二、右擊movie添加新文件,概要,文本文件,選擇路徑並命名爲app.rc;

  三、打開app.rc,只添加一條指令爲

IDI_ICON1 ICON DISCARDABLE "i.ico"

  四、構建文件

  五、打開pro文件,在最尾處添加

RC_FILE=\
    app.rc

  六、從新構建發佈,就能夠獲得新的exe圖標:

 

  這個簡單的gif播放器來源於Qt自帶的example中,經過從頭至尾本身的建立,對於熟練掌握Qt的一些基本操做仍是頗有好處的,最後附上生成文件,也算是個小軟件了吧,但願你們能夠一塊兒學習,共同進步!

  百度雲:http://pan.baidu.com/share/link?shareid=4263268927&uk=3641520234

  Eggif 1.0:http://pan.baidu.com/share/link?shareid=3500459208&uk=3641520234

相關文章
相關標籤/搜索