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…...
uniapp 对接腾讯云IM群组成员管理(增删改查)
UniApp 实战:腾讯云IM群组成员管理(增删改查) 一、前言 在社交类App开发中,群组成员管理是核心功能之一。本文将基于UniApp框架,结合腾讯云IM SDK,详细讲解如何实现群组成员的增删改查全流程。 权限校验…...
基于大模型的 UI 自动化系统
基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...
论文解读:交大港大上海AI Lab开源论文 | 宇树机器人多姿态起立控制强化学习框架(二)
HoST框架核心实现方法详解 - 论文深度解读(第二部分) 《Learning Humanoid Standing-up Control across Diverse Postures》 系列文章: 论文深度解读 + 算法与代码分析(二) 作者机构: 上海AI Lab, 上海交通大学, 香港大学, 浙江大学, 香港中文大学 论文主题: 人形机器人…...
css实现圆环展示百分比,根据值动态展示所占比例
代码如下 <view class""><view class"circle-chart"><view v-if"!!num" class"pie-item" :style"{background: conic-gradient(var(--one-color) 0%,#E9E6F1 ${num}%),}"></view><view v-else …...
椭圆曲线密码学(ECC)
一、ECC算法概述 椭圆曲线密码学(Elliptic Curve Cryptography)是基于椭圆曲线数学理论的公钥密码系统,由Neal Koblitz和Victor Miller在1985年独立提出。相比RSA,ECC在相同安全强度下密钥更短(256位ECC ≈ 3072位RSA…...
SciencePlots——绘制论文中的图片
文章目录 安装一、风格二、1 资源 安装 # 安装最新版 pip install githttps://github.com/garrettj403/SciencePlots.git# 安装稳定版 pip install SciencePlots一、风格 简单好用的深度学习论文绘图专用工具包–Science Plot 二、 1 资源 论文绘图神器来了:一行…...
【Redis技术进阶之路】「原理分析系列开篇」分析客户端和服务端网络诵信交互实现(服务端执行命令请求的过程 - 初始化服务器)
服务端执行命令请求的过程 【专栏简介】【技术大纲】【专栏目标】【目标人群】1. Redis爱好者与社区成员2. 后端开发和系统架构师3. 计算机专业的本科生及研究生 初始化服务器1. 初始化服务器状态结构初始化RedisServer变量 2. 加载相关系统配置和用户配置参数定制化配置参数案…...
UR 协作机器人「三剑客」:精密轻量担当(UR7e)、全能协作主力(UR12e)、重型任务专家(UR15)
UR协作机器人正以其卓越性能在现代制造业自动化中扮演重要角色。UR7e、UR12e和UR15通过创新技术和精准设计满足了不同行业的多样化需求。其中,UR15以其速度、精度及人工智能准备能力成为自动化领域的重要突破。UR7e和UR12e则在负载规格和市场定位上不断优化…...
论文笔记——相干体技术在裂缝预测中的应用研究
目录 相关地震知识补充地震数据的认识地震几何属性 相干体算法定义基本原理第一代相干体技术:基于互相关的相干体技术(Correlation)第二代相干体技术:基于相似的相干体技术(Semblance)基于多道相似的相干体…...
虚拟电厂发展三大趋势:市场化、技术主导、车网互联
市场化:从政策驱动到多元盈利 政策全面赋能 2025年4月,国家发改委、能源局发布《关于加快推进虚拟电厂发展的指导意见》,首次明确虚拟电厂为“独立市场主体”,提出硬性目标:2027年全国调节能力≥2000万千瓦࿰…...
