示例学QT系列一——Movie Example

看了一些QT的教程和视频,当时个人感觉都听懂了,但真正开发过程中好像不知道去用它的一些特性和库,或者说又忘记怎么使用了~这几年的开发经验告诉我,代码放在具体项目中才能记忆深刻(是一长串“无情”的代码直观呢?还是一个绚丽的界面和功能呢?)

刚好QT本身提供了非常多的示例源码,于是乎突发奇想,是不是把这些示例代码都搞懂,算不算熟悉QT了呢~(因为我之前有4年多的WPF和C++开发经验,所以示例代码看上去不是特别吃力,学习中总感觉QT是WPF的C++版,果然好的框架的设计模式都是潜移默化的)。但愿此系列可以坚持更新,fighting!!!

Movie Example(导入视频并控制播放)

1、功能描述:

 如上图所示,下面一排控件有:视频导入、播放、暂停、重置、删除的功能;上面依次是视频播放窗口、是否FitToWindow、Current frame(播放条与视频同步);

2、代码实现:

 从主函数开始看比较简单

int main(int argc, char *argv[])
{
    QApplication app(argc, argv);
    MoviePlayer player;
    player.show();
    return app.exec();
}
QApplication接受命令行参数,MoviePlayer生成实例show出来后,调用QApplication的exec方法循环~

  MoviePlayer是本实例中比较关键的类:不仅要完成功能逻辑,还有布局代码;它的头文件比较清晰

#ifndef MOVIEPLAYER_H//预编译头
#define MOVIEPLAYER_H

#include <QWidget>

QT_BEGIN_NAMESPACE  //使用QT的命名空间,类的前置声明以减少编译依赖
class QCheckBox;
class QGridLayout;
class QHBoxLayout;
class QLabel;
class QMovie;
class QSlider;
class QSpinBox;
class QToolButton;
class QVBoxLayout;
QT_END_NAMESPACE

class MoviePlayer : public QWidget
{
    Q_OBJECT

public:
    MoviePlayer(QWidget *parent = 0);
    void openFile(const QString &fileName);

private slots:
    void open();
    void goToFrame(int frame);
    void fitToWindow();
    void updateButtons();
    void updateFrameSlider();

private:
    void createControls();
    void createButtons();

    /*
    类的成员变量 略...
    */
};

#endif

比起原生的C++,上述代码中多了slots关键字,还有一个宏Q_OBJECT。在Qt的程序中如果使用了信号与反应槽就必须在类的定义中声明这个宏,不过如果你声明了该宏但在程序中并没有信号与槽,对程序也不会有任何影响(同样必须继承QObject,本例中的QWdiget是QObject的子类),这样修饰有什么用 这就不得不提QT中很重要的机制

 信号与槽函数

        信号(Signal)就是在特定情况下被发射的事件。
        槽(Slot)就是对信号响应的函数。与一般的C++函数是一样的,可以定义在类的任何部分(public、private 或 protected),可以具有任何参数,也可以被直接调用。槽函数与一般的函数不同的是:槽函数可以与一个信号关联,当信号被发射时,关联的槽函数被自动执行。

 信号与槽函数怎么关联呢?QT中用QObject::connect() 函数实现

QObject::connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));

 其中,sender 是发射信号的对象的名称,signal() 是信号名称。信号可以看做是特殊的函数,需要带括号,有参数时还需要指明参数。receiver 是接收信号的对象名称,slot() 是槽函数的名称,需要带括号,有参数时还需要指明参数。

 SIGNAL 和 SLOT 是 Qt 的宏,用于指明信号和槽,并将它们的参数转换为相应的字符串。

 回归示例

巴拉巴拉说了很多, 具体怎么使用到咱们的功能中呢?例如,上述功能中有一个是导入本地视频(我们想要点击文件夹Button弹出文件框供我们导入),有前端开发经验的不难想到,是不是可以捕获Button的点击事件,再执行相应逻辑;本例中open函数就是导入button的点击事件所关联的槽函数。代码如下添加

connect(openButton, SIGNAL(clicked()), this, SLOT(open()));
//open函数处理openButton实例发出的点击事件

//open槽函数的处理
void MoviePlayer::open()
{
    QString fileName = QFileDialog::getOpenFileName(this, tr("Open a Movie"),
                               currentMovieDirectory);
    if (!fileName.isEmpty())
        openFile(fileName);
}

 按照这个套路或者说这种机制,我们可以先把所有需要关注的事件都与声明的槽函数关联,就有了如下代码

//movie的frameChanged与stateChanged事件
connect(movie, SIGNAL(frameChanged(int)), this, SLOT(updateFrameSlider()));
connect(movie, SIGNAL(stateChanged(QMovie::MovieState)),
            this, SLOT(updateButtons()));

connect(fitCheckBox, SIGNAL(clicked()), this, SLOT(fitToWindow()));
//frameSlider speedSpinBox的valueChanged事件
connect(frameSlider, SIGNAL(valueChanged(int)), this, SLOT(goToFrame(int)));
connect(speedSpinBox, SIGNAL(valueChanged(int)),
            movie, SLOT(setSpeed(int)));

//一些点击事件
connect(playButton, SIGNAL(clicked()), movie, SLOT(start()));
connect(stopButton, SIGNAL(clicked()), movie, SLOT(stop()));
connect(quitButton, SIGNAL(clicked()), this, SLOT(close()));

 一切看上去都是那么合理~ 但有一个问题,button的点击事件我们很容易想到,但像movie的frameChangedstateChanged事件从何得知呢?以我4年WPF的开发经验,这些类有哪些事件,哪些事件又是对我们有用的?这类问题没有很好的办法,只有多看帮助文档、多在项目中用到才能知道。

重要的类:首先是视频窗口类QMovie,构造函数形参是父控件指针;使用到的接口

                         setCacheMode:设置缓存类型(QMovie::CacheAll与QMovie::None)
                         stop():顾名思义,停止
                         start():开始
                         state():当前状态
                         isValid():视频是否合法
                         setFileName:设置打开的文件路径
                         currentFrameNumber:当前帧数
                         goToFrame(int frame):调到第几帧

        用于打开文件窗口QFileDialog::getOpenFileName


QString QFileDialog::getOpenFileName (
	QWidget * parent = 0,                 //用于指定父组件
	const QString & caption = QString(),  //对话框的标题
	const QString & dir = QString(),      //对话框显示时默认打开的目录
	const QString & filter = QString(),   //对话框的后缀名过滤器
​	QString * selectedFilter = 0,         //默认选择的过滤器
​	Options options = 0 );                //对话框的一些参数设定,比如只显示文件夹等

        OK,可以具体看下槽函数的功能,点击open Button触发click事件,走到open()函数,打开文件Dialog,用户选择视频文件后走入openFile(name)函数,对QMovie对象设置新的属性后播放,更新FrameSlider与其他状态按钮。一条工作流END                      还有一个功能fitToWindow,这里把QMovie包在movieLabel中,设置QLabel的setScaledContents属性即可设置是否自适应~

3、其他        

读过设计模式的小伙伴应该熟悉,QT中的信号和槽其实是观察者模式(发布\订阅),观察者模式定义了一对多的依赖关系,当一个对象改变时,它的所有依赖者都会收到通知并自动更新。类似很多人订阅了一个公众号,一旦公众号发送消息,订阅的人都会收到消息。这样做的好处:减少了耦合,让代码结构更加的清晰~

WPF中常用的事件也是用的这种机制,当然QT中也有事件的概念,大同小异。上面示例代码看着不是很舒服,主要是它把布局代码与逻辑写在一起了(如何将设计与逻辑分开,类似WPF中的xmal),QT有自己的前台qml,继续学习吧~

个人感觉WPF很多设计和库都挺好用的,但跨平台做得不好再加上用的是C#,所以在国内不火。。。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值