一、配置文件更改

用到多媒体的话,需要修改配置文件的第一行,后面加一句 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. qt ctrl键中途松开如何监控 qt暂停按钮_进度条


  3. qt ctrl键中途松开如何监控 qt暂停按钮_qt ctrl键中途松开如何监控_02


  4. 整体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设为想要的图片

qt ctrl键中途松开如何监控 qt暂停按钮_ide_03


qt ctrl键中途松开如何监控 qt暂停按钮_qt ctrl键中途松开如何监控_04

  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

qt ctrl键中途松开如何监控 qt暂停按钮_qt ctrl键中途松开如何监控_05

六、问题和思考

  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 ctrl键中途松开如何监控 qt暂停按钮_qt_06