本程序在ubuntu12.04、Qt5以及win7 64bit、Qt4均測試通過。
最近閑來無事,想自己找幾個Qt的小項目做做,於是就從Qt自帶的演示程序着手。在Qt的自帶example有一個movie的小程序,地址在xxx\QT\Examples\x.x\widgets\movie或/opt/Qt/5.1.0/gcc/examples/widgets/widgets中。這是一個用來播放gif文件的程序,在ubuntu運行界面如下:
其基本功能有載入文件、暫停、停止、退出、快進,顯示播放速度以及根據窗口挑戰文件大小。
這個播放器已經實現了大多數的功能,但是我在調試過程中發現它的暫停功能並不能實現,快進快退只能使用QSpinBox很不方便,最好集成到button中去。窗口調整的功能有點費,因為一般我們都希望窗口適應文件的大小而不是文件根據窗口大小來調整,而且使用這樣的調整會使得圖像失真,不好看。最后內置的movie鍵不是很好看,可以換一下。以下是最后改進后的界面:
OK,現在就開始。首先創建一個Qt Gui程序命名為movie。選擇QWidget並命名為movieplayer,ui可選可不選,我們這不選:
創建文件后進入movieplayer.h,首先聲明一下要用到的庫文件,這邊一次性把接下來所有要用到的都聲明一下:
#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格式的!
將可執行文件替換成自己想要的圖標需要以下幾個步驟:
1、將你的ico文件放入根目錄,我用的是i.icon;
2、右擊movie添加新文件,概要,文本文件,選擇路徑並命名為app.rc;
3、打開app.rc,只添加一條指令為
IDI_ICON1 ICON DISCARDABLE "i.ico"
4、構建文件
5、打開pro文件,在最尾處添加
RC_FILE=\
app.rc
6、重新構建發布,就可以得到新的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