QT:音视频播放器

目录

一.播放器设计

二.需要使用的控件

三.选择视频

四.播放视频

五.暂停视频

六.关闭视频

七.播放状态设置

八.切换视频(上一首)

九.切换视频(下一首)

十.设置视频滑块

十一.更新滑块显示

十二.实现效果

十三.代码设计

1.mainwindow.h

2.mainwindow.cpp


一.播放器设计

播放器主要包含了媒体播放器的基本功能,如选择视频,播放、停止、快进、快退、播放列表管理、时间显示、状态指示等。

mainwindow.ui

二.需要使用的控件

QSlider是一个用于用户输入的控件,主要用于实现滑动条功能。滑动条允许用户通过滑动滑块在一组连续的值中选择一个值。QSlider通常用于控制数值的调整,如音量、亮度、滚动条等。

QLabel是一个用于显示文本或者图像的控件。它是Qt框架中用于界面布局和显示信息的基本组件之一。QLabel可以用来显示各种类型的信息,如文本、图片、图标等。

QListView是一个用于显示和浏览项目列表的视图控件。它通常与QModel(如QAbstractListModel或QStandardItemModel)一起使用来管理数据,并允许用户通过滚动和点击来浏览这些数据。

QPushButton是一个常用的标准控件,用于创建按钮,用户可以通过点击按钮来触发事件。QPushButton可以显示文本、图标或者两者的组合。

三.选择视频

  1. 打开一个文件对话框,让用户选择一个或多个视频文件。
  2. 如果用户选择了文件,则将文件路径添加到一个QStringList对象中。
  3. 遍历这些文件路径,并将每个文件的名称添加到一个QStandardItemModel(假设名为model)中。
  4. 设置一个多媒体播放器(假设名为player)的媒体内容为第一个文件的内容,准备播放。

四.播放视频

五.暂停视频

六.关闭视频

七.播放状态设置

八.切换视频(上一首)

  1. 获取和检查索引:首先获取当前在列表视图中选中的项目的索引,然后检查这个索引是否有效。如果有效,说明用户已经选中了一个项目。

  2. 处理有效索引:如果当前索引有效,代码将计算前一个项目的索引,并确保这个索引在列表范围内循环,即使当前处于第一项也能回到最后一项。然后,它将这个前一个项目设置为列表视图的当前选中项,并获取该项对应的媒体文件路径,最后通过媒体播放器对象播放这个媒体文件。

  3. 处理无效索引:如果当前索引无效,即没有选中任何项目,代码将自动选择列表中的最后一项,并播放与该项对应的媒体文件。这确保了即使在没有任何选中项的情况下,用户也能通过播放列表的最后一项来开始播放。

九.切换视频(下一首)

1.当用户点击"下一项"按钮时被调用。它首先获取当前选中的列表项索引,如果索引有效,则获取下一项的索引,如果下一项索引无效(即已经是最后一项),则跳转到列表的第一项。

2.将列表视图的当前索引设置为新的索引,并播放与该索引对应的媒体文件。如果当前索引无效(即列表为空或没有选中任何项),它将选择并播放列表的第一项。

十.设置视频滑块

十一.更新滑块显示

1.更新滑块显示

2.计算已经观看时间和剩余时间

3.格式化时间

4.更新已观看时间和剩余时间都标签

十二.实现效果

十三.代码设计

1.mainwindow.h

cpp 复制代码
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QDialog>
#include <QWidget>
#include <QMediaPlayer>
#include <QVideoWidget>
#include <QPushButton>
#include <QLineEdit>
#include <QFileDialog>
#include <QUrl>
#include <QListView>
#include <QStandardItem>
#include <QStandardItemModel>


QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

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

private slots:
    void on_play_clicked();

    void on_stop_clicked();

    void on_pushButton_clicked();

    void on_close_clicked();

    void on_horizontalSlider_actionTriggered(int position);

    void on_listView_doubleClicked(const QModelIndex &index);

    void updatePosition(qint64 position);
    void labelstateChanged(QMediaPlayer::State state);

    QString formatTime(int seconds);

    void on_previous_clicked();

    void on_next_clicked();

private:
    QMediaPlayer *player;
    QVideoWidget *videoWidget;
    QString videoPath;

    QStandardItemModel *model; // 声明 model 变量

    Ui::MainWindow *ui;

};
#endif // MAINWINDOW_H

2.mainwindow.cpp

cpp 复制代码
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QMediaPlayer>
#include <QVideoWidget>
#include <QDebug>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    player = new QMediaPlayer(this);
    videoWidget = new QVideoWidget(this);

    // 设置视频输出
    player->setVideoOutput(videoWidget);


    connect(player, &QMediaPlayer::positionChanged,this, &MainWindow::updatePosition);
    connect(player, &QMediaPlayer::stateChanged,this,&MainWindow::labelstateChanged);
    connect(ui->listView, &QListView::doubleClicked, this, &MainWindow::on_listView_doubleClicked);

    connect(ui->horizontalSlider, &QSlider::valueChanged, this, &MainWindow::on_horizontalSlider_actionTriggered);

    // 初始化模型
    model = new QStandardItemModel(this);
    ui->listView->setModel(model); // 设置 listView 的模型

    videoWidget->move(QPoint(10, 50));

    // 设置视频Widget的尺寸
    videoWidget->resize(280, 280);
}

MainWindow::~MainWindow()
{
    delete ui;
    // 这里确保删除player和videoWidget以避免内存泄露
    delete player;
    delete videoWidget;
}

void MainWindow::on_play_clicked()
{
   player->play();
}

void MainWindow::on_stop_clicked()
{
    player->pause();
}

void MainWindow::on_pushButton_clicked()
{
    
    // 使用QFileDialog获取文件路径列表
    QStringList filePaths = QFileDialog::getOpenFileNames(this, tr("选择视频文件"), ""/*, tr("MP4 Files (*.mp4);;All Files (*)")*/);
    
    // 检查是否选择了文件
    if (!filePaths.isEmpty()) {
        // 遍历所有选中的文件路径
        for (const QString &filePath : filePaths) {
            // 创建一个新的QStandardItem,包含文件名
            QStandardItem *item = new QStandardItem(QFileInfo(filePath).fileName());
            
            // 将该项添加到模型中,这里假设model是QStandardItemModel的实例
            model->appendRow(item); // 将视频文件名称添加到模型中
        }
        
        // 设置播放器的媒体内容为第一个文件的内容,准备播放
        player->setMedia(QMediaContent(QUrl::fromLocalFile(filePaths.first())));
    }

}

void MainWindow::on_close_clicked()
{
    player->stop();
}

void MainWindow::on_horizontalSlider_actionTriggered(int position)
{
    player->setPosition(position * 1000);
}


void MainWindow::on_listView_doubleClicked(const QModelIndex &index)
{

    if (index.isValid()) {
        QStandardItem *item = model->itemFromIndex(index);
        if (item) {
            // 获取列表中当前选中项的文件路径
            QString filePath =  "E:/lzy/MediaPlayer/Test/" + item->text();  //videoPath;
            // 检查文件是否存在
            if (QFile::exists(filePath)) {
                player->setMedia(QMediaContent(QUrl::fromLocalFile(filePath)));
                player->play();
            } else {
                qDebug() << "File does not exist: " << filePath;
            }
        }
    }
}


void MainWindow::updatePosition(qint64 position)
{ // 更新滑块显示
     ui->horizontalSlider->setMaximum(player->duration() / 1000);
    // ui->horizontalSlider->setValue(position / 1000);


    // 计算已观看时间和剩余时间
    int currentSeconds = position / 1000;
    int totalSeconds = player->duration() / 1000;
    int remainingSeconds = totalSeconds - currentSeconds;

    // 格式化时间
    QString currentTimeStr = formatTime(currentSeconds);
    QString remainingTimeStr = formatTime(remainingSeconds);
    QString totalSecondsStr = formatTime(totalSeconds);

    // 更新已观看时间和剩余时间的标签
    ui->labelCurrentTime->setText(currentTimeStr);
    ui->labelRemainingTime->setText(remainingTimeStr);
    ui->labeltotalTime->setText(totalSecondsStr);

}

QString MainWindow::formatTime(int seconds)
{
    int minutes = seconds / 60;
    int secs = seconds % 60;
    return QString("%1:%2").arg(minutes, 2, 10, QChar('0')).arg(secs, 2, 10, QChar('0'));
}


void MainWindow::labelstateChanged(QMediaPlayer::State state)
{
    switch (state) {
    case QMediaPlayer::StoppedState:
        ui->labelstate->setText(tr("停止状态!"));
        break;
    case QMediaPlayer::PlayingState:
        ui->labelstate->setText(tr("播放状态!"));
        break;
    case QMediaPlayer::PausedState:
        ui->labelstate->setText(tr("暂停状态!"));
        break;
    default: break;
    }
}

void MainWindow::on_previous_clicked()
{
    // 获取当前选中的索引
    QModelIndex currentIndex = ui->listView->currentIndex();
    // 检查当前索引是否有效
    if (currentIndex.isValid()) {
        // 获取当前选中项的上一项的索引
        int currentRow = currentIndex.row();
        int previousRow = (currentRow - 1 + model->rowCount()) % model->rowCount(); // 使用模运算确保索引循环
        QModelIndex previousIndex = model->index(previousRow, currentIndex.column());
        // 选择上一项
        ui->listView->setCurrentIndex(previousIndex);
        // 播放上一项
        QStandardItem *previousItem = model->itemFromIndex(previousIndex);
        if (previousItem) {
            // 设置媒体内容为上一项的视频路径
            QString filePath = "E:/lzy/MediaPlayer/Test/" + previousItem->text(); // 假设文件路径是这样设置的
            player->setMedia(QMediaContent(QUrl::fromLocalFile(filePath)));
            player->play();
        }
    } else {
        // 如果当前索引无效,可能是没有选中任何项目,可以选择最后一项
        QModelIndex lastIndex = model->index(model->rowCount() - 1, 0);
        ui->listView->setCurrentIndex(lastIndex);
        // 播放最后一项
        QStandardItem *lastItem = model->itemFromIndex(lastIndex);
        if (lastItem) {
            QString filePath = "E:/lzy/MediaPlayer/Test/" + lastItem->text(); // 假设文件路径是这样设置的
            player->setMedia(QMediaContent(QUrl::fromLocalFile(filePath)));
            player->play();
        }
    }
}

void MainWindow::on_next_clicked()
{
    // 获取当前选中的索引
    QModelIndex currentIndex = ui->listView->currentIndex();

    // 检查当前索引是否有效
    if (currentIndex.isValid()) {
        // 获取当前选中项的下一项的索引
        QModelIndex nextIndex = model->index(currentIndex.row() + 1, currentIndex.column());

        // 如果下一项索引无效,则跳转到最后一项
        if (!nextIndex.isValid()) {
            nextIndex = model->index(0, 0);
        }

        // 选择下一项
        ui->listView->setCurrentIndex(nextIndex);

        // 播放下一项
        QStandardItem *nextItem = model->itemFromIndex(nextIndex);
        if (nextItem) {
            // 设置媒体内容为下一项的视频路径
            QString filePath = "E:/lzy/MediaPlayer/Test/" + nextItem->text(); // 假设文件路径是这样设置的
            player->setMedia(QMediaContent(QUrl::fromLocalFile(filePath)));
            player->play();
        }
    } else {
        // 如果当前索引无效,可能是没有选中任何项目,可以选择第一项
        QModelIndex firstIndex = model->index(0, 0);
        ui->listView->setCurrentIndex(firstIndex);

        // 播放第一项
        QStandardItem *firstItem = model->itemFromIndex(firstIndex);
        if (firstItem) {
            QString filePath = "E:/lzy/MediaPlayer/Test/" + firstItem->text(); // 假设文件路径是这样设置的
            player->setMedia(QMediaContent(QUrl::fromLocalFile(filePath)));
            player->play();
        }
    }
}
相关推荐
明月看潮生2 分钟前
青少年编程与数学 02-003 Go语言网络编程 15课题、Go语言URL编程
开发语言·网络·青少年编程·golang·编程与数学
南宫理的日知录13 分钟前
99、Python并发编程:多线程的问题、临界资源以及同步机制
开发语言·python·学习·编程学习
逊嘘30 分钟前
【Java语言】抽象类与接口
java·开发语言·jvm
van叶~32 分钟前
算法妙妙屋-------1.递归的深邃回响:二叉树的奇妙剪枝
c++·算法
Half-up32 分钟前
C语言心型代码解析
c语言·开发语言
knighthood200143 分钟前
解决:ros进行gazebo仿真,rviz没有显示传感器数据
c++·ubuntu·ros
Source.Liu1 小时前
【用Rust写CAD】第二章 第四节 函数
开发语言·rust
monkey_meng1 小时前
【Rust中的迭代器】
开发语言·后端·rust
余衫马1 小时前
Rust-Trait 特征编程
开发语言·后端·rust
monkey_meng1 小时前
【Rust中多线程同步机制】
开发语言·redis·后端·rust