QT:音视频播放器
目录
一.播放器设计
二.需要使用的控件
三.选择视频
四.播放视频
五.暂停视频
六.关闭视频
七.播放状态设置
八.切换视频(上一首)
九.切换视频(下一首)
十.设置视频滑块
十一.更新滑块显示
十二.实现效果
十三.代码设计
1.mainwindow.h
2.mainwindow.cpp
一.播放器设计
播放器主要包含了媒体播放器的基本功能,如选择视频,播放、停止、快进、快退、播放列表管理、时间显示、状态指示等。
mainwindow.ui
二.需要使用的控件
QSlider是一个用于用户输入的控件,主要用于实现滑动条功能。滑动条允许用户通过滑动滑块在一组连续的值中选择一个值。QSlider通常用于控制数值的调整,如音量、亮度、滚动条等。
QLabel是一个用于显示文本或者图像的控件。它是Qt框架中用于界面布局和显示信息的基本组件之一。QLabel可以用来显示各种类型的信息,如文本、图片、图标等。
QListView是一个用于显示和浏览项目列表的视图控件。它通常与QModel(如QAbstractListModel或QStandardItemModel)一起使用来管理数据,并允许用户通过滚动和点击来浏览这些数据。
QPushButton是一个常用的标准控件,用于创建按钮,用户可以通过点击按钮来触发事件。QPushButton可以显示文本、图标或者两者的组合。
三.选择视频
- 打开一个文件对话框,让用户选择一个或多个视频文件。
- 如果用户选择了文件,则将文件路径添加到一个QStringList对象中。
- 遍历这些文件路径,并将每个文件的名称添加到一个QStandardItemModel(假设名为
model
)中。 - 设置一个多媒体播放器(假设名为
player
)的媒体内容为第一个文件的内容,准备播放。
四.播放视频
五.暂停视频
六.关闭视频
七.播放状态设置
八.切换视频(上一首)
-
获取和检查索引:首先获取当前在列表视图中选中的项目的索引,然后检查这个索引是否有效。如果有效,说明用户已经选中了一个项目。
-
处理有效索引:如果当前索引有效,代码将计算前一个项目的索引,并确保这个索引在列表范围内循环,即使当前处于第一项也能回到最后一项。然后,它将这个前一个项目设置为列表视图的当前选中项,并获取该项对应的媒体文件路径,最后通过媒体播放器对象播放这个媒体文件。
-
处理无效索引:如果当前索引无效,即没有选中任何项目,代码将自动选择列表中的最后一项,并播放与该项对应的媒体文件。这确保了即使在没有任何选中项的情况下,用户也能通过播放列表的最后一项来开始播放。
九.切换视频(下一首)
1.当用户点击“下一项”按钮时被调用。它首先获取当前选中的列表项索引,如果索引有效,则获取下一项的索引,如果下一项索引无效(即已经是最后一项),则跳转到列表的第一项。
2.将列表视图的当前索引设置为新的索引,并播放与该索引对应的媒体文件。如果当前索引无效(即列表为空或没有选中任何项),它将选择并播放列表的第一项。
十.设置视频滑块
十一.更新滑块显示
1.更新滑块显示
2.计算已经观看时间和剩余时间
3.格式化时间
4.更新已观看时间和剩余时间都标签
十二.实现效果
十三.代码设计
1.mainwindow.h
#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
#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();
}
}
}