给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

相关文章
相关标签/搜索