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_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic: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();}}
}
相关文章:
QT:音视频播放器
目录 一.播放器设计 二.需要使用的控件 三.选择视频 四.播放视频 五.暂停视频 六.关闭视频 七.播放状态设置 八.切换视频(上一首) 九.切换视频(下一首) 十.设置视频滑块 十一.更新滑块显示 十二.实现效果 十三.代码设计 1.mainwindow.h 2.mainwindow.cpp 一.播放…...
大模型入门 ch 03:注意力机制
本文是github上的大模型教程LLMs-from-scratch的学习笔记,教程地址:教程链接 Chapter 3: Attention Mechanism 本文首先从固定参数的注意力机制说起,然后拓展到可以训练的注意力机制,然后加入掩码mask,最后…...
STM32点亮第一个LED
还有第二个,并轮换。 准备入门STM32,于是拿出了买到手至少2年的洋桃M1板子,STM32F103C8T6 配置有3个LED,3个按钮,RS232,RS485,CAN,有JTAG,有RTC电池,IO口引…...
[Linux]:动静态库
✨✨ 欢迎大家来到贝蒂大讲堂✨✨ 🎈🎈养成好习惯,先赞后看哦~🎈🎈 所属专栏:Linux学习 贝蒂的主页:Betty’s blog 1. 动静态库的介绍 一般而言,库分为动态库和静态库。 在Linux当中…...
windows 显示进程地址空间
windows 显示进程地址空间 windows 显示进程地址空间 文章目录 windows 显示进程地址空间显示进程地址空间 显示进程地址空间 /* 3-ProcessInfo.cpp 显示进程地址空间 */#include "..\\CommonFiles\\CmnHdr.h" #include "..\\CommonFiles\\Toolhelp.h"#i…...
Android 12 SystemUI下拉状态栏禁止QuickQSPanel展开
1.概述 遇到需求,QuickQSPanel首次下拉后展示快捷功能模块以后就是显示QuickQSPanel,而不展开QSPanel,接下来要从下滑手势下拉出状态栏分析功能实现。也就是直接是展开状态。 2、涉及核心类 frameworks\base\packages\SystemUI\src\com\and…...
二分思想与相关问题(下)
接下来详细讲解几道比较难的例题,仔细体会二分和其他概念混合在一起的趣味。 下面这道题涉及了“碎片拼接”的概念,很妙,也很难想。 P r o b l e m 5 Problem5 Problem5 同时运行N台电脑的最长时间 LeetCode2141 你有 n 台电脑。给你整数 n…...
【算法专题】搜索算法
二叉树剪枝 LCR 047. 二叉树剪枝 - 力扣(LeetCode) 本题要求我们将全部为0的二叉树去掉,也就是剪枝,当我们举一个具体的例子进行模拟时,会发现,只关注于对其中一个子树的根节点进行剪枝,由于我…...
B2064 斐波那契数列
题目描述 斐波那契数列是指这样的数列:数列的第一个和第二个数都为 11,接下来每个数都等于前面 22 个数之和。 给出一个正整数 aa,要求斐波那契数列中第 aa 个数是多少。 输入格式 第 11 行是测试数据的组数 nn,后面跟着 nn 行…...
Spark的介绍
一、分布式的思想 不管是数据也好,计算也好,都没有最大的电脑,而是多个小电脑组合而成。 存储:将3T的文件拆分成若干个小文件,例如每500M一个小文件,将这些小文件存储在不同的机器上 。 -- HDFS 计算&#…...
SpringBoot项目是如何启动
启动步骤 概念 运行main方法,初始化SpringApplication 从spring.factories读取listener ApplicationContentInitializer运行run方法读取环境变量,配置信息创建SpringApplication上下文预初始化上下文,将启动类作为配置类进行读取调用 refres…...
科技之光,照亮未来之路“2024南京国际人工智能展会”
全球科技产业的版图正以前所未有的速度重构,而位于中国东部沿海经济带的江浙沪地区,作为科技创新与产业升级的高地,始终站在这一浪潮的最前沿。2024年,这一区域的科技盛宴——“2024南京人工智能展会”即将在南京国际博览中心盛大…...
在深度学习计算机视觉的语义分割中,Boundary和Edge的区别是?
在深度学习中的计算机视觉任务中,语义分割中的 Boundary 和 Edge 其实有一些相似之处,但它们的定义和使用场景略有不同。下面是两者的区别: 1. Boundary(边界) 定义:Boundary 是指一个对象或区域的边界&a…...
【JAVA入门】Day41 - 字节缓冲流和字符缓冲流
【JAVA入门】Day41 - 字节缓冲流和字符缓冲流 文章目录 【JAVA入门】Day41 - 字节缓冲流和字符缓冲流一、缓冲流的体系结构二、字节缓冲流2.1 字节缓冲流提高效率的底层原理 三、字符缓冲流 在IO流体系中,FileInputStream,FileOutputStream,F…...
collocate join,bucket join,broadcast join,shuffle join对比分析
在分布式计算和大数据处理中,尤其是在使用像 Apache Spark、Hive 等大数据处理框架时,Join 操作是非常常见的。根据数据分布方式和执行机制,Join 操作可以分为不同的类型,如 Collocate Join、Bucket Join、Broadcast Join 和 Shuffle Join。以下是它们的详细对比分析: 1.…...
微信自动通过好友和自动拉人进群,微加机器人这个功能太好用了
又发现一个好用的功能,之前就想找一个这种工具,现在发现可以利用微加机器人的两个功能来实现,分别是加好友和关键词拉群 首先 微加机器人的专业版 > 功能 > 加好友设置 可以设置一个关键词通过,这样别人加好友的时候只需要输入制定内…...
R语言统计分析——功效分析3(相关、线性模型)
参考资料:R语言实战【第2版】 1、相关性 pwr.r.test()函数可以对相关性分析进行功效分析。格式如下: pwr.r.test(n, r, sig.level, power, alternative) 其中,n是观测数目,r是效应值(通过线性相关系数衡量࿰…...
Django创建模型
1、根据创建好应用模块 python manage.py startapp tests 2、在models文件里创建模型 from django.db import modelsfrom book.models import User# Create your models here. class Tests(models.Model):STATUS_CHOICES ((0, 启用),(1, 停用),# 更多状态...)add_time mode…...
盘点2024年大家都在用的短视频剪辑工具
你现在休息的时间是不是都靠短视频来消遣?看着看着你就会发现短视频制作好像我也可以了吧?这次我就介绍一些简单好操作的短视频剪辑工具。 1.FOXIT视频剪辑 连接直达>>https://www.pdf365.cn/foxitclip/ 短视频剪辑其实也不难,只需…...
“左侧文字横向”的QTabWidget
左侧用 QToolButton 组, 右侧用 QStackedWidget,信号槽绑定切换页面 可定制化高 QButtonGroup* btnGp new QButtonGroup(this);btnGp->addButton(ui->btn1, 0);btnGp->addButton(ui->btn2, 1);btnGp->addButton(ui->btn3, 2);connect…...
【Linux】shell脚本忽略错误继续执行
在 shell 脚本中,可以使用 set -e 命令来设置脚本在遇到错误时退出执行。如果你希望脚本忽略错误并继续执行,可以在脚本开头添加 set e 命令来取消该设置。 举例1 #!/bin/bash# 取消 set -e 的设置 set e# 执行命令,并忽略错误 rm somefile…...
ssc377d修改flash分区大小
1、flash的分区默认分配16M、 / # df -h Filesystem Size Used Available Use% Mounted on /dev/root 1.9M 1.9M 0 100% / /dev/mtdblock4 3.0M...
解锁数据库简洁之道:FastAPI与SQLModel实战指南
在构建现代Web应用程序时,与数据库的交互无疑是核心环节。虽然传统的数据库操作方式(如直接编写SQL语句与psycopg2交互)赋予了我们精细的控制权,但在面对日益复杂的业务逻辑和快速迭代的需求时,这种方式的开发效率和可…...
【第二十一章 SDIO接口(SDIO)】
第二十一章 SDIO接口 目录 第二十一章 SDIO接口(SDIO) 1 SDIO 主要功能 2 SDIO 总线拓扑 3 SDIO 功能描述 3.1 SDIO 适配器 3.2 SDIOAHB 接口 4 卡功能描述 4.1 卡识别模式 4.2 卡复位 4.3 操作电压范围确认 4.4 卡识别过程 4.5 写数据块 4.6 读数据块 4.7 数据流…...
Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信
文章目录 Linux C语言网络编程详细入门教程:如何一步步实现TCP服务端与客户端通信前言一、网络通信基础概念二、服务端与客户端的完整流程图解三、每一步的详细讲解和代码示例1. 创建Socket(服务端和客户端都要)2. 绑定本地地址和端口&#x…...
C#中的CLR属性、依赖属性与附加属性
CLR属性的主要特征 封装性: 隐藏字段的实现细节 提供对字段的受控访问 访问控制: 可单独设置get/set访问器的可见性 可创建只读或只写属性 计算属性: 可以在getter中执行计算逻辑 不需要直接对应一个字段 验证逻辑: 可以…...
MySQL 知识小结(一)
一、my.cnf配置详解 我们知道安装MySQL有两种方式来安装咱们的MySQL数据库,分别是二进制安装编译数据库或者使用三方yum来进行安装,第三方yum的安装相对于二进制压缩包的安装更快捷,但是文件存放起来数据比较冗余,用二进制能够更好管理咱们M…...
macOS 终端智能代理检测
🧠 终端智能代理检测:自动判断是否需要设置代理访问 GitHub 在开发中,使用 GitHub 是非常常见的需求。但有时候我们会发现某些命令失败、插件无法更新,例如: fatal: unable to access https://github.com/ohmyzsh/oh…...
鸿蒙HarmonyOS 5军旗小游戏实现指南
1. 项目概述 本军旗小游戏基于鸿蒙HarmonyOS 5开发,采用DevEco Studio实现,包含完整的游戏逻辑和UI界面。 2. 项目结构 /src/main/java/com/example/militarychess/├── MainAbilitySlice.java // 主界面├── GameView.java // 游戏核…...
Mysql故障排插与环境优化
前置知识点 最上层是一些客户端和连接服务,包含本 sock 通信和大多数jiyukehuduan/服务端工具实现的TCP/IP通信。主要完成一些简介处理、授权认证、及相关的安全方案等。在该层上引入了线程池的概念,为通过安全认证接入的客户端提供线程。同样在该层上可…...
