QT学习笔记——①进度条可拖动点击②有暂停按钮 的视频播放器

Posted 玛丽莲茼蒿

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了QT学习笔记——①进度条可拖动点击②有暂停按钮 的视频播放器相关的知识,希望对你有一定的参考价值。

一、配置文件更改

用到多媒体的话,需要修改配置文件的第一行,后面加一句 sql multimedia multimediawidgets
修改后的配置文件前3行如下

QT       += core gui sql multimedia multimediawidgets

//下面都不用改
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++11

二、UI基本设计(待会会根据功能回来修改部分属性)

  1. 找一个普通的widget,然后右键 “提升为” QVideoWidget

  2. 整体UI是这样的,布局就差不多自己搞一下吧

三、视频播放进度条跟着动、拖动进度条视频跟着动

  1. mainwindow.cpp文件
    啥代码都不写的话,你打开一个视频,会发现随着视频的播放,进度条动都不动。所以要进行下面的操作
    (1)去帮助手册查看horizental slider这个控件的信号,发现slidermoved这个信号可以传回来进度条的最新位置。根据这个位置去改变视频的进度,用setPosition
    (2)去帮助手册查看player的信号,发现positionChanged这个信号可以返回视频的最新播放进度,可以用来设置进度条的值setValue
    上面两个看起来有点像“互锁”的感觉,但是各搞各的,可以实现。
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMediaPlayer>   //
#include <QFileDialog>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    player =new QMediaPlayer;
    player->setMedia(QMediaContent(QUrl::fromLocalFile("D:\\\\Program Files\\\\Apache Software Foundation\\\\Tomcat 8.5\\\\webapps\\\\MyWebsite\\\\大耳朵图图.mp3")));
    player->setVideoOutput(ui->widget);
    player->play();

    //视频长度改变,打印出来
    connect(player,SIGNAL(durationChanged(qint64)),this,SLOT(onPlayerDurationChanged(qint64)));
    //进度条位置改变,打印出来
    connect(player,SIGNAL(positionChanged(qint64)),this,SLOT(onPlayerPositionChanged(qint64)));
    //拖动进度条,改变视频的进度
    connect(ui->horizontalSlider,SIGNAL(sliderMoved(int)),this,SLOT(onSliderMoved(int)));
}

MainWindow::~MainWindow()
{
    delete ui;
}

void MainWindow::onPlayerDurationChanged(qint64 duration){
    qDebug()<<duration;
    ui->horizontalSlider->setMaximum(duration);  //最大值
}

/*
 * 获取视频进度
*/
void MainWindow::onPlayerPositionChanged(qint64 position){
    qDebug()<<position;
    ui->horizontalSlider->setValue(position);  //进度条进度跟着变
}

/*
 * 根据进度条的value,改变视频的进度
*/
void MainWindow::onSliderMoved(int value){
    player->setPosition(value);  //视频跟着进度条变
}
  1. 头文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include<QMediaPlayer>  //

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    QMediaPlayer *player;  //!!!    
private slots:
 
   void onPlayerDurationChanged(qint64 duration); //!!!
   void onPlayerPositionChanged(qint64 position);  //
   void onSliderMoved(int value);
   
};
#endif // MAINWINDOW_H

  1. 这个时候你会发现,实现了“进度条随着视频的播放而变化”这一功能,但是拖不动进度条哈哈哈哈。解决方案见下面的问题和思考。

四、实现暂停/播放按钮

  1. 安排好按钮上需要的图片资源
    (1)之前创建过资源文件夹了,里面也创建了一个子文件夹/pic用来存放图片,把想用的图片拖进去。而且必须拖进去,比如下面这行代码:
 ui->pushButton->setStyleSheet("border-image: url(F:\\\\QT project\\\\day03_video\\\\Resources\\\\play.jpg)");

用的是本地路径,这个是不管用的。
要改成:

 ui->pushButton->setStyleSheet("border-image: url(:/pic/play.jpg)");

注意,子文件夹/pic在本地文件管理器中是看不到的
(2)资源放入/pic文件夹后,更改pushButtonstyleSheet属性,将border-image设为想要的图片

  1. mainwindow.cpp文件(在之前进度条的代码上改的))
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMediaPlayer>   //
#include <QFileDialog>
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    player =new QMediaPlayer;
    player->setMedia(QMediaContent(QUrl::fromLocalFile("D:\\\\Program Files\\\\Apache Software Foundation\\\\Tomcat 8.5\\\\webapps\\\\MyWebsite\\\\大耳朵图图.mp3")));
    player->setVideoOutput(ui->widget);
    player->play();

    //视频播放or暂停状态切换,不断获取,存在state这个成员变量里
    connect(player,SIGNAL(stateChanged(QMediaPlayer::State)),this,SLOT(onPlayerStateChanged(QMediaPlayer::State)));
    //视频长度改变,打印出来
    connect(player,SIGNAL(durationChanged(qint64)),this,SLOT(onPlayerDurationChanged(qint64)));
    //进度条位置改变,打印出来
    connect(player,SIGNAL(positionChanged(qint64)),this,SLOT(onPlayerPositionChanged(qint64)));
    //拖动进度条,改变视频的进度
    connect(ui->horizontalSlider,SIGNAL(sliderMoved(int)),this,SLOT(onSliderMoved(int)));
    //按下播放按钮,改变按钮的状态;因为视频的状态被player这个播放器不断获取,所以onPlayerStateChanged一直被调用,相应的图片也会改变
    connect(ui->pushButton,SIGNAL(clicked()),this,SLOT(onPlay()));
}

MainWindow::~MainWindow()
{
    delete ui;
}

/*
 * 切换视频状态(播放->暂停,暂停->播放)
*/
void MainWindow::onPlay(){
    if(player->state()== QMediaPlayer::PlayingState){
        player->pause();
    }else{
        player->play();
    }
}

/*
 * 跟踪视频状态(播放or暂停)
*/
void MainWindow::onPlayerStateChanged(QMediaPlayer::State state){
   this->state = state;
   if(state == QMediaPlayer::PlayingState){
       ui->pushButton->setStyleSheet("border-image: url(:/pic/play.jpg)");
   }else{
       ui->pushButton->setStyleSheet("border-image: url(:/pic/pause.jpg)");
   }
}

/*
 *获取视频长度
*/
void MainWindow::onPlayerDurationChanged(qint64 duration){
    qDebug()<<duration;
    ui->horizontalSlider->setMaximum(duration);  //最大值
}

/*
 * 获取视频进度
*/
void MainWindow::onPlayerPositionChanged(qint64 position){
    qDebug()<<position;
    ui->horizontalSlider->setValue(position);  //进度条进度跟着变
}

/*
 * 根据进度条的value,改变视频的进度
*/
void MainWindow::onSliderMoved(int value){
    player->setPosition(value);  //视频跟着进度条变
}

  1. 头文件
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include<QMediaPlayer>  //

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    Ui::MainWindow *ui;
    QMediaPlayer *player;  //!!!
    QMediaPlayer::State state;  //!!!

private slots:
   void onPlay();  //!!!
   void onPlayerStateChanged(QMediaPlayer::State state); //!!!
   void onPlayerDurationChanged(qint64 duration); //!!!
   void onPlayerPositionChanged(qint64 position);  //
   void onSliderMoved(int value);
};
#endif // MAINWINDOW_H

五、实现进度条的“点哪打哪”

前面实现的视频播放器只能拖动进度条,不能像市面上常见的播放器一样点哪里播放哪里,下面就要实现这个功能。

  1. 首先,UI界面不用动了
  2. QSlider的mousePressEvent()默认的方式是,点击之后跳跃一定的固定距离,无法实现“指哪打哪”,因此我们需要对mousePressEvent()进行重写。
  3. 不知道可不可以简单的在mainwindow.cpp里直接重载mousePressEvent()这个函数。我没尝试,我直接用的下面这个方法(转载自博客
    (1)给QSlider添加一个子类。在项目窗口中,右击工程的根目录,添加新文件,选择C++ Class,填写基类为QSlider。我这里将其命名为CustomSlider。自动生成了customslider.hcustomslider.cpp这两个文件。

(2)直接把代码粘进去。

customslider.h

#ifndef CUSTOMSLIDER_H
#define CUSTOMSLIDER_H
#include <QSlider>
#include <QMouseEvent>
#include <QCoreApplication>

class CustomSlider : public QSlider
{
    Q_OBJECT
public:
    CustomSlider(QWidget *parent = 0) : QSlider(parent)
    {
    }
protected:
    void mousePressEvent(QMouseEvent *ev);//重写QSlider的mousePressEvent事件
signals:
    void costomSliderClicked();//自定义的鼠标单击信号,用于捕获并处理
};

#endif // CUSTOMSLIDER_H

customslider.cpp

#include "customslider.h"

void CustomSlider::mousePressEvent(QMouseEvent *ev)
{
    //注意应先调用父类的鼠标点击处理事件,这样可以不影响拖动的情况
    QSlider::mousePressEvent(ev);
    //获取鼠标的位置,这里并不能直接从ev中取值(因为如果是拖动的话,鼠标开始点击的位置没有意义了)
    double pos = ev->pos().x() / (double)width();
    //让进度条直接蹦过来
    setValue(pos * (maximum() - minimum()) + minimum());  
    //发送自定义的鼠标单击信号
    emit costomSliderClicked();
}

(3)再就是在头文件mainwindow.h里加一个新的槽函数,就是点击进度条触发的槽函数。

private slots:
   void sliderClicked();

(4)编写槽函数

/*
* slider点击事件发生后,改变视频的进度
*/
void MainWindow::sliderClicked(){
    player->setPosition(ui->horizontalSlider->value());
}

(5)连接信号和槽函数

//自定义的信号costomSliderClicked()
    connect(ui->horizontalSlider,SIGNAL(costomSliderClicked()),this,SLOT(sliderClicked()));

(6)非常重要的一点!!因为我们继承了QSlider这个类,生成了新的类CustomSlider,所以UI里的进度条的类提升一下,不然的话和代码不配套。
右击进度条,选择提升为,自己写上提升为CustomSlider

六、问题和思考

  1. 拖动进度条实现视频进度改变的槽函数写好了,信号连好了,但是拖动不了进度条。
    一开始在找信号和函数的问题,确保了没有问题(照老师抄的)以后。开始想,进度条拖不动应该是控件本身的问题吧。于是根据直觉改了空间horizental slider的一个属性,把mouseTracking那里打上勾就可以了哈哈哈哈
  2. 一开始播放按钮想用toolButton,但是它的信号只有一个triggered(*action),里面的参数我不太懂,就换了pushButton,用cliked()信号。
  3. 如果出现问题别忘了看程序输出窗口!!
  4. 使用下面这行代码,
player->setMedia(QMediaContent(QUrl::fromLocalFile("D:\\\\Program Files\\\\Apache Software Foundation\\\\Tomcat 8.5\\\\webapps\\\\MyWebsite\\\\大耳朵图图.mp3")));

mp3可以播放,但视频mp4不能播放,并且报错

DirectShowPlayerService::doRender: Unresolved error code 0x80040266

这个是不能解析的错误,一开始我以为是fromLocalFile这个函数不能解析路径,一直在改这个函数的参数哼,后来发现我理解错了,不能解析的意思是视频没法解析!!!需要下载一个解析视频的程序,LAVFilters,放哪都行,下载完立马奏效!!。当然,除了LAVFilters,其他解析视频的程序也可以。

以上是关于QT学习笔记——①进度条可拖动点击②有暂停按钮 的视频播放器的主要内容,如果未能解决你的问题,请参考以下文章

微信小程序(原生)——video视频禁止拖动进度条可全屏观看等视频播放结束事件数据监听显示播放时长固定倍速视频去除黑边等

Unity3d - RPG项目学习笔记(十六)

qq小窝腾讯视频切换进度方法

QT学习笔记——添加资源文件

FFmpeg+Qt视频进度条控制——点击跳转和拖动跳转

tkinter窗口鼠标拖动就会暂停