avatar

Qt大作业:影音播放器

软件类别:本地视频文件播放器


软件设计、实现的思路和方法:

类名:player,继承自 QMainWindow
自定义类:video,继承自 QVideoWidget


*注:

  • 播放部分格式文件需要安装解码器,安装包(LAVfilters)已打包一起发送
  • 影音文件已打包发送,可直接用于软件测试

主要功能和槽函数:

private slots:
void openFile();//打开文件
void fullScr();//全屏
void play_and_pause();//播放和暂停
void minimize();//小窗置顶和取消
void positionChanged(qint64 position);//进度条位置设置,随视频文件播放变化
void setPosition(qint64 position);//获取播放位置
void getDuration();//获取视频文件长度
void on_progress_sliderMoved(int position);//进度条滑动改变视频进度
void next_song();//下一项

1、界面设计

  • ui-designer
    image_1dfopk44sog1qmj1nve1kqb1k22f.png-244.9kB

  • 布局代码

    //将widget设置为中心layout
    widget=new QWidget;
    this->setCentralWidget(widget);

    //水平布局,控制按钮
    QBoxLayout *ctlLayout = new QHBoxLayout;
    ctlLayout->addWidget(ui->open);
    ctlLayout->addWidget(ui->playBtn);
    ctlLayout->addWidget(ui->next);
    ctlLayout->addWidget(ui->progress);
    ctlLayout->addWidget(ui->fullscreenBtn);
    ctlLayout->addWidget(ui->min);

    //调整水平布局部件比例
    ctlLayout->setStretchFactor(ui->playBtn,1);
    ctlLayout->setStretchFactor(ui->progress,10);
    ctlLayout->setStretchFactor(ui->fullscreenBtn,1);
    ctlLayout->setStretchFactor(ui->min,1);


    //垂直布局:视频播放器、水平控制布局
    QBoxLayout *mainLayout = new QVBoxLayout;
    mainLayout->addWidget(videowidget);
    mainLayout->addLayout(ctlLayout);

    //设置布局
    widget->setLayout(mainLayout);
    this->setWindowTitle("lxm的播放器");

    //设置按钮透明
    ui->playBtn->setFlat(true);
    ui->open->setFlat(true);
    ui->fullscreenBtn->setFlat(true);
    ui->min->setFlat(true);
    ui->next->setFlat(true);

    //设置图标
    //所有图片均采用相对路径,并保存在资源文件下
    QIcon icon1;
    icon1.addFile(":/image/video_player_783px_1234870_easyicon.net.png");
    setWindowIcon(icon1);

    QIcon icon;
    icon.addFile(":/image/next_596px_1229355_easyicon.net.png");
    ui->playBtn->setIcon(icon);

    QIcon icon3;
    icon3.addFile(":/image/File_Box_808px_1145730_easyicon.net.png");
    ui->open->setIcon(icon3);

    icon.addFile(":/image/fullscreen_128px_1181910_easyicon.net.png");
    ui->fullscreenBtn->setIcon(icon);

    QIcon icon2;
    icon2.addFile(":/image/button_arrow_up_200px_1189268_easyicon.net.png");
    ui->min->setIcon(icon2);

    QIcon icon7;
    icon7.addFile(":/image/next_596px_1229354_easyicon.net.png");
    ui->next->setIcon(icon7);



    //设置按钮文字提示
    ui->open->setToolTip(tr("打开文件"));
    ui->playBtn->setToolTip(tr("播放"));
    ui->fullscreenBtn->setToolTip(tr("全屏"));
    ui->min->setToolTip(tr("小窗置顶"));
    ui->next->setToolTip(tr("下一项"));
  • 软件界面:
    image_1dforeqmf115qdrq17auod71ioc19.png-12.1kB


2、文件批量载入

  • 信号和槽:
    QObject::connect(ui->open,SIGNAL (clicked()),this,SLOT(openFile()));
  • 实现思路:
    见代码注释

  • 功能截图:
    image_1dforgil91no4af2ut12tp18m11m.png-121.7kB

  • 实现方法:

    void player::openFile()
    {
    //打开工程文件所在文件夹,文件夹中放置了影音文件
    //list中存入文件名,使用QStringList和getOpenFileNames实现批量导入
    QStringList list=QFileDialog::getOpenFileNames(this);
    for(int k=0;k<list.size();k++)
    {
    //path保存歌曲路径
    QString path=QDir::toNativeSeparators(list.at(k));
    //将该路径倒入到playlist中
    playlist->addMedia(QUrl::fromLocalFile(path));
    //同路径中提取出文件名
    QString name=path.split("\\").last();
    }
    //导入后自动开始播放
    if(mediaplayer->state()!=1)//判断当前是否出于播放状态
    play_and_pause();//播放
    }

3、视频播放和暂停

  • 信号和槽:
    QObject::connect(ui->playBtn,SIGNAL(clicked()),this,SLOT(play_and_pause()));
  • 实现思路:
    当视频为停止或暂停状态时,按钮play图标为“播放”,提示为“播放”,点击事件可以是视频变为播放状态;当视频为播放状态时,改变为暂停图标,按钮提示为“暂停”。
  • 快捷键:空格
  • 功能截图:
    播放状态
    屏幕截图(145).png-160.7kB
    暂停状态
    屏幕截图(146).png-167.6kB
  • 实现方法:
    void player::play_and_pause()
    {

    switch (mediaplayer->state()) {
    case 1://playing
    {
    QIcon icon;
    icon.addFile(":/image/wedding_video_783px_1219421_easyicon.net.png");//改变图标
    ui->playBtn->setIcon(icon);
    mediaplayer->pause();//暂停播放
    ui->playBtn->setToolTip(tr("播放"));
    break;
    }
    default://stop&paused
    {
    QIcon icon;
    icon.addFile(":/image/pause_button_195px_1197803_easyicon.net.png");
    ui->playBtn->setIcon(icon);
    mediaplayer->play();//播放
    ui->playBtn->setToolTip(tr("暂停"));
    }
    }
    }

4、进度条位置的调节

  • 信号和槽:
    QObject::connect(mediaplayer,SIGNAL(positionChanged(qint64)),this,SLOT(positionChanged(qint64)));

    QObject::connect(mediaplayer,SIGNAL(durationChanged(qint64)),this,SLOT(getDuration()));
  • 实现思路:
    获取视频总时长和滑块可调节长度计算出换算比例,使滑块位置和视频播放位置相对应,具体见下方代码注释
  • 实现方法:
    void player::positionChanged(qint64 position)
    {
    //这里的position指的是视频的播放对应的时间
    //按照比例设置进度条位置
    ui->progress->setValue(position/time2);
    }

    void player::setPosition(qint64 position)
    {
    //获取mediaplayer进度调整位置
    mediaplayer->setPosition(position);
    }
    void player::on_progress_sliderMoved(int position)
    {
    //position为滑块位置,position*time2为滑块位置应对应的视频时刻
    setPosition(position*time2);
    }


    void player::getDuration()
    {
    //获取视频文件时间长度
    time=mediaplayer->duration();
    //horizontalbar的长度为100,time2为比例系数
    time2=(int)time/100;
    }

    5、小窗置顶功能

  • 信号和槽:
    QObject::connect(ui->min,SIGNAL(clicked()),this,SLOT(minimize()));
  • 功能描述:
    将该程序置顶于所有窗口,点击置顶按钮会提示“双击快捷操作”,使用双击方式置顶\取消置顶则不会提示,使使用更加流畅
  • 功能截图:
    • 未置顶状态
      屏幕截图(148).png-137.7kB
    • 置顶状态(可以在看视频的同时操作其它软件)
      image_1dforu1c91dpsg56191bni21vvj41.png-414.2kB
  • 实现方法:
    //置顶功能
    void player::up()
    {
    if (m_flags == NULL)
    {
    //将播放器设置为置顶
    m_flags = windowFlags();
    setWindowFlags(m_flags | Qt::WindowStaysOnTopHint);
    show();
    //变换图标和按钮提示
    QIcon icon2;
    icon2.addFile(":/image/down.png");
    ui->min->setIcon(icon2);
    ui->min->setToolTip(tr("取消窗口置顶"));
    }
    else
    {
    //取消播放器置顶
    m_flags = nullptr;
    setWindowFlags(m_flags);
    show();
    //变换图标和按钮提示
    QIcon icon2;
    icon2.addFile(":/image/button_arrow_up_200px_1189268_easyicon.net.png");
    ui->min->setIcon(icon2);
    ui->min->setToolTip(tr("小窗置顶"));
    }
    }
    //槽函数
    void player::minimize()
    {
    QMessageBox::about(this, tr("Tips"), tr("双击进入/退出小窗"));
    up();
    }
    //鼠标双击快捷操作
    void player::mouseDoubleClickEvent(QMouseEvent*)
    {
    up();
    }

6、全屏功能

  • 信号和槽:
    QObject::connect(ui->fullscreenBtn,SIGNAL(clicked()),this,SLOT(fullScr()));
  • 实现思路:
    首先对mediaplayer的全屏状态进行判断,若为非全屏状态,使用enter键或点击全屏按钮均可进入全屏,若为全屏状态,点击enter键退出全屏。点击全屏按钮会提示“快捷键enter”,而直接点击enter键进入全屏则不会,使使用更加流畅
  • 功能截图:
    image_1dfos09ubggj2c149p4brj6d4e.png-1611.1kB
  • 实现方法:
    player类:
    void player::fullScr()//全屏功能
    {
    if(mediaplayer->state()==1)//若正在播放,则可进入全屏状态
    {
    //全屏前需要取消小窗置顶
    setWindowFlags(nullptr);
    show();
    //全屏
    videowidget->setFullScreen(true);
    QMessageBox::about(this, tr("Tips"), tr("enter键进入/退出全屏"));
    }
    else {
    {
    //当前不在播放视频,无法进入全屏模式
    videowidget->setFullScreen(false);
    }
    }
    }
    在video类也写入槽函数:
    解决全屏后player类父窗口无法接收到信号的问题
    void  video::keyPressEvent(QKeyEvent *keyset)//全屏和全屏退出
    {
    if(keyset->key()==16777220)//回车键
    {
    if(this->isFullScreen())//如果当前出于全屏状态
    {
    //退出全屏
    this->setWindowFlags (Qt::SubWindow);
    this->showNormal();
    }
    else
    {
    //进入全屏
    this->setFullScreen(true);
    }
    }
    }

7、播放下一项

  • 信号和槽
    QObject::connect(ui->next,SIGNAL(clicked()),this,SLOT(next_song()));
  • 实现思路
    将进度条拉至最后
  • 截图:
    屏幕截图(150).png-119kB
  • 实现方法
    void player::next_song()
    {
    setPosition(100*time2);
    }
  • 注意事项
//需将mediaplayer设置为循环播放,否则会在播放最后一项时再点击next会导致程序退出
playlist->setPlaybackMode(QMediaPlaylist::Loop);

8、可作为音频播放器使用

  • 功能描述:支持音频播放,支持播放列表中同时存在视频和音频
  • 功能截图:
    image_1dfotiu3b1v81j6g9nrtns4o157.png-8.6kB

遇到的问题和解决方法

(*注:部分细节问题以列入代码注释中)

  • ui->designer中的控件运行之后界面不显示
    • 被设置为中心layout的widget所覆盖,需添加QVBoxLayout,分离widget和按钮控件
  • 进度条无法正常使用
    • 需正确设置进度条位置和视频播放位置的换算比例(time2)
  • durationChanged()函数执行后,文件时间长度值time依然为0
    • 重写时间获取槽函数
      QObject::connect(mediaplayer,SIGNAL(positionChanged(qint64)),this,SLOT(positionChanged(qint64)));

      QObject::connect(mediaplayer,SIGNAL(durationChanged(qint64)),this,SLOT(getDuration()));

      void player::getDuration()
      {
      //获取视频文件时间长度
      time=mediaplayer->duration();
      //horizontalbar的长度为100,time2为比例系数
      time2=(int)time/100;
      }
  • 全屏后无法退出
    • 全屏后信号被子窗口(video)接收,父窗口(player)无法接收到信号,而全屏相关函数的信号接收对象是父窗口,故无法接收到信号。
    • 所以,只需在video类中也写入全屏函数即可,详见“6、全屏功能”
  • 程序每次运行只能播放一首曲目
    • 改用QStringList记录文件名,优化playlist写入方式,详见上文“2、文件批量载入”
  • “下一项”功能受限,导入的文件只能播放一次
    • 需将mediaplayer设置为循环播放,否则会在播放最后一项时再点击next会导致程序退出
      playlist->setPlaybackMode(QMediaPlaylist::Loop);
Author: Michelle19l
Link: https://gitee.com/michelle19l/michelle19l/2019/08/31/Qt/Qt大作业报告/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.
Donate
  • 微信
    微信
  • 支付寶
    支付寶