当前位置: 首页 > news >正文

开源 C++ QT Widget 开发(十五)多媒体--音频播放

   文章的目的为了记录使用C++ 进行QT Widget 开发学习的经历。临时学习,完成app的开发。开发流程和要点有些记忆模糊,赶紧记录,防止忘记。
 

 相关链接:

开源 C++ QT Widget 开发(一)工程文件结构-CSDN博客

开源 C++ QT Widget 开发(二)基本控件应用-CSDN博客

开源 C++ QT Widget 开发(三)图表--波形显示器-CSDN博客

开源 C++ QT Widget 开发(四)文件--二进制文件查看编辑-CSDN博客

 开源 C++ QT Widget 开发(五)通讯--串口调试-CSDN博客

开源 C++ QT Widget 开发(六)通讯--TCP调试-CSDN博客

开源 C++ QT Widget 开发(七)线程--多线程及通讯-CSDN博客

开源 C++ QT Widget 开发(八)网络--Http文件下载-CSDN博客

开源 C++ QT Widget 开发(九)图表--仪表盘-CSDN博客

开源 C++ QT Widget 开发(十)IPC进程间通信--共享内存-CSDN博客

开源 C++ QT Widget 开发(十一)进程间通信--Windows 窗口通信-CSDN博客

开源 C++ QT Widget 开发(十二)图表--环境监测表盘-CSDN博客

开源 C++ QT Widget 开发(十三)IPC通讯--本地套接字 (Local Socket)

开源 C++ QT Widget 开发(十四)多媒体--录音机

开源 C++ QT Widget 开发(十五)多媒体--音频播放



推荐链接:

开源 java android app 开发(一)开发环境的搭建-CSDN博客

开源 java android app 开发(二)工程文件结构-CSDN博客

开源 java android app 开发(三)GUI界面布局和常用组件-CSDN博客

开源 java android app 开发(四)GUI界面重要组件-CSDN博客

开源 java android app 开发(五)文件和数据库存储-CSDN博客

开源 java android app 开发(六)多媒体使用-CSDN博客

开源 java android app 开发(七)通讯之Tcp和Http-CSDN博客

开源 java android app 开发(八)通讯之Mqtt和Ble-CSDN博客

开源 java android app 开发(九)后台之线程和服务-CSDN博客

开源 java android app 开发(十)广播机制-CSDN博客

开源 java android app 开发(十一)调试、发布-CSDN博客

开源 java android app 开发(十二)封库.aar-CSDN博客

推荐链接:

开源C# .net mvc 开发(一)WEB搭建_c#部署web程序-CSDN博客

开源 C# .net mvc 开发(二)网站快速搭建_c#网站开发-CSDN博客

开源 C# .net mvc 开发(三)WEB内外网访问(VS发布、IIS配置网站、花生壳外网穿刺访问)_c# mvc 域名下不可訪問內網,內網下可以訪問域名-CSDN博客

开源 C# .net mvc 开发(四)工程结构、页面提交以及显示_c#工程结构-CSDN博客

开源 C# .net mvc 开发(五)常用代码快速开发_c# mvc开发-CSDN博客

内容:Qt实现的WAV音频播放器应用程序。实现win10系统下,播放wav音频的功能。

目录:

1.功能介绍

2.核心代码分析

3.所有源码

4.显示效果

一.功能介绍

这是一个基于QMediaPlayer的音频播放器,主要功能包括:

音频播放控制:播放、停止、进度控制

文件检查:验证音频文件的存在和有效性

状态监控:实时显示播放状态和进度

错误处理:完善的错误检测和处理机制

日志系统:详细的运行日志记录

二、核心代码分析
头文件 (mainwindow.h)
 

class MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void on_playButton_clicked();                      // 播放按钮点击void updatePlaybackProgress();                     // 更新播放进度void handlePlayerStateChanged(QMediaPlayer::State state); // 播放状态变化void handlePlayerError(QMediaPlayer::Error error); // 错误处理private:Ui::MainWindow *ui;QMediaPlayer *player;          // 媒体播放器核心QTimer *progressTimer;         // 进度更新计时器QString audioFilePath;         // 音频文件路径void logMessage(const QString &message); // 日志记录bool checkAudioFile();                   // 文件检查
};


函数功能详细分析
1. 构造函数 MainWindow::MainWindow()
功能:初始化播放器界面和组件

MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow), player(new QMediaPlayer(this))        // 创建媒体播放器, progressTimer(new QTimer(this))       // 创建进度计时器
{ui->setupUi(this);setWindowTitle("16K WAV音频播放器 - Qt5.14"); // 设置窗口标题audioFilePath = QDir::currentPath() + "/Output.wav"; // 设置默认文件路径ui->filePathLabel->setText("文件: " + audioFilePath); // 显示文件路径player->setVolume(80); // 设置默认音量(80%)// 信号槽连接connect(player, SIGNAL(stateChanged(QMediaPlayer::State)),this, SLOT(handlePlayerStateChanged(QMediaPlayer::State)));connect(player, SIGNAL(error(QMediaPlayer::Error)),this, SLOT(handlePlayerError(QMediaPlayer::Error)));connect(progressTimer, &QTimer::timeout, this, &MainWindow::updatePlaybackProgress);// UI初始化ui->playButton->setText("开始播放");ui->statusLabel->setText("就绪");ui->progressBar->setValue(0);// 文件检查if (checkAudioFile()) {logMessage("音频文件检查正常,准备就绪");} else {ui->playButton->setEnabled(false); // 文件无效时禁用播放按钮}
}


2. 析构函数 MainWindow::~MainWindow()
功能:安全清理资源

MainWindow::~MainWindow()
{if (player->state() == QMediaPlayer::PlayingState) {player->stop(); // 如果正在播放,先停止}delete ui;
}


3. checkAudioFile() - 音频文件检查
功能:验证音频文件的存在和有效性

bool MainWindow::checkAudioFile()
{QFileInfo fileInfo(audioFilePath);if (!fileInfo.exists()) {logMessage("错误:音频文件不存在 - " + audioFilePath);ui->statusLabel->setText("错误:文件不存在");return false;}if (fileInfo.size() == 0) {logMessage("警告:音频文件为空");ui->statusLabel->setText("警告:文件为空");return false;}logMessage(QString("找到音频文件:%1 (%2 字节)").arg(audioFilePath).arg(fileInfo.size()));return true;
}


4. on_playButton_clicked() - 播放控制
功能:处理播放/停止按钮点击事件

void MainWindow::on_playButton_clicked()
{if (player->state() == QMediaPlayer::PlayingState) {// 停止播放logMessage("用户停止播放");player->stop();progressTimer->stop();ui->playButton->setText("开始播放");} else {// 开始播放if (!checkAudioFile()) {logMessage("播放失败:音频文件不可用");return;}logMessage("开始播放音频文件...");player->setMedia(QUrl::fromLocalFile(audioFilePath)); // 设置媒体源if (player->mediaStatus() == QMediaPlayer::InvalidMedia) {logMessage("错误:无法加载媒体文件");ui->statusLabel->setText("错误:无效的媒体文件");return;}player->play(); // 开始播放progressTimer->start(100); // 启动进度更新计时器(100ms间隔)logMessage("播放器启动完成");}
}


5. updatePlaybackProgress() - 进度更新
功能:实时更新播放进度显示

void MainWindow::updatePlaybackProgress()
{if (player->duration() > 0) {qint64 position = player->position(); // 当前位置(毫秒)qint64 duration = player->duration(); // 总时长(毫秒)int seconds = position / 1000;        // 转换为秒int totalSeconds = duration / 1000;// 格式化时间显示 (MM:SS / MM:SS)ui->timeLabel->setText(QString("%1:%2 / %3:%4").arg(seconds / 60, 2, 10, QLatin1Char('0'))  // 当前分钟.arg(seconds % 60, 2, 10, QLatin1Char('0'))  // 当前秒.arg(totalSeconds / 60, 2, 10, QLatin1Char('0')) // 总分钟.arg(totalSeconds % 60, 2, 10, QLatin1Char('0')) // 总秒);// 计算进度百分比int progress = (duration > 0) ? static_cast<int>(position * 100 / duration) : 0;ui->progressBar->setValue(progress);// 每秒记录一次进度日志(避免过于频繁)static int lastSecond = -1;if (seconds != lastSecond) {lastSecond = seconds;logMessage(QString("播放进度: %1% (%2/%3 秒)").arg(progress).arg(seconds).arg(totalSeconds));}}
}



6. handlePlayerStateChanged() - 状态变化处理
功能:响应播放器状态变化

void MainWindow::handlePlayerStateChanged(QMediaPlayer::State state)
{switch (state) {case QMediaPlayer::StoppedState:logMessage("播放停止");ui->statusLabel->setText("播放完成");ui->playButton->setText("开始播放");progressTimer->stop(); // 停止进度更新ui->progressBar->setValue(100); // 进度条置满break;case QMediaPlayer::PlayingState:logMessage("播放进行中...");ui->statusLabel->setText("正在播放");ui->playButton->setText("停止播放");logMessage(QString("媒体时长: %1 毫秒").arg(player->duration()));break;case QMediaPlayer::PausedState:logMessage("播放暂停");ui->statusLabel->setText("播放暂停");ui->playButton->setText("继续播放");break;}
}


7. handlePlayerError() - 错误处理
功能:处理播放器错误

void MainWindow::handlePlayerError(QMediaPlayer::Error error)
{QString errorMsg;switch (error) {case QMediaPlayer::NoError:return;case QMediaPlayer::ResourceError:errorMsg = "资源错误:无法访问媒体文件";break;case QMediaPlayer::FormatError:errorMsg = "格式错误:不支持的媒体格式"; // WAV格式可能不支持break;case QMediaPlayer::NetworkError:errorMsg = "网络错误";break;case QMediaPlayer::AccessDeniedError:errorMsg = "访问被拒绝:没有足够的权限";break;default:errorMsg = "未知错误";break;}logMessage(errorMsg);ui->statusLabel->setText("播放错误");ui->playButton->setText("开始播放");QMessageBox::warning(this, "播放错误", errorMsg); // 弹出错误对话框
}




8. logMessage() - 日志记录
功能:统一的日志记录系统

void MainWindow::logMessage(const QString &message)
{QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");QString logEntry = QString("[%1] %2").arg(timestamp).arg(message);ui->logTextEdit->append(logEntry); // 添加到UI日志框qDebug() << logEntry;              // 输出到控制台// 自动滚动到日志底部QTextCursor cursor = ui->logTextEdit->textCursor();cursor.movePosition(QTextCursor::End);ui->logTextEdit->setTextCursor(cursor);
}


 

三、所有源码

1.  pro文件

QT       += core gui
QT       += core gui multimedia
greaterThan(QT_MAJOR_VERSION, 4): QT += widgetsCONFIG += c++11# The following define makes your compiler emit warnings if you use
# any Qt feature that has been marked deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS# You can also make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0SOURCES += \main.cpp \mainwindow.cppHEADERS += \mainwindow.hFORMS += \mainwindow.ui# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

2. mainwindow.h文件

#ifndef MAINWINDOW_H
#define MAINWINDOW_H#include <QMainWindow>
#include <QMediaPlayer>
#include <QTimer>
#include <QFileInfo>QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACEclass MainWindow : public QMainWindow
{Q_OBJECTpublic:explicit MainWindow(QWidget *parent = nullptr);~MainWindow();private slots:void on_playButton_clicked();void updatePlaybackProgress();void handlePlayerStateChanged(QMediaPlayer::State state);void handlePlayerError(QMediaPlayer::Error error);private:Ui::MainWindow *ui;QMediaPlayer *player;QTimer *progressTimer;QString audioFilePath;void logMessage(const QString &message);bool checkAudioFile();
};#endif // MAINWINDOW_H

3.mianwindow.cpp文件

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDir>
#include <QDateTime>
#include <QFileInfo>
#include <QDebug>
#include <QMessageBox>MainWindow::MainWindow(QWidget *parent): QMainWindow(parent), ui(new Ui::MainWindow), player(new QMediaPlayer(this)), progressTimer(new QTimer(this))
{ui->setupUi(this);// 设置窗口标题setWindowTitle("16K WAV音频播放器 - Qt5.14");// 设置音频文件路径audioFilePath = QDir::currentPath() + "/Output.wav";ui->filePathLabel->setText("文件: " + audioFilePath);// 配置播放器player->setVolume(80); // 设置音量 0-100// 连接信号槽connect(player, SIGNAL(stateChanged(QMediaPlayer::State)),this, SLOT(handlePlayerStateChanged(QMediaPlayer::State)));connect(player, SIGNAL(error(QMediaPlayer::Error)),this, SLOT(handlePlayerError(QMediaPlayer::Error)));connect(progressTimer, &QTimer::timeout, this, &MainWindow::updatePlaybackProgress);// 初始化UI状态ui->playButton->setText("开始播放");ui->statusLabel->setText("就绪");ui->progressBar->setValue(0);// 检查音频文件if (checkAudioFile()) {logMessage("音频文件检查正常,准备就绪");} else {ui->playButton->setEnabled(false);}
}MainWindow::~MainWindow()
{if (player->state() == QMediaPlayer::PlayingState) {player->stop();}delete ui;
}bool MainWindow::checkAudioFile()
{QFileInfo fileInfo(audioFilePath);if (!fileInfo.exists()) {logMessage("错误:音频文件不存在 - " + audioFilePath);ui->statusLabel->setText("错误:文件不存在");return false;}if (fileInfo.size() == 0) {logMessage("警告:音频文件为空");ui->statusLabel->setText("警告:文件为空");return false;}logMessage(QString("找到音频文件:%1 (%2 字节)").arg(audioFilePath).arg(fileInfo.size()));return true;
}void MainWindow::on_playButton_clicked()
{if (player->state() == QMediaPlayer::PlayingState) {// 停止播放logMessage("用户停止播放");player->stop();progressTimer->stop();ui->playButton->setText("开始播放");} else {// 开始播放if (!checkAudioFile()) {logMessage("播放失败:音频文件不可用");return;}logMessage("开始播放音频文件...");player->setMedia(QUrl::fromLocalFile(audioFilePath));if (player->mediaStatus() == QMediaPlayer::InvalidMedia) {logMessage("错误:无法加载媒体文件");ui->statusLabel->setText("错误:无效的媒体文件");return;}player->play();// 启动进度更新计时器progressTimer->start(100);logMessage("播放器启动完成");}
}void MainWindow::updatePlaybackProgress()
{if (player->duration() > 0) {qint64 position = player->position();qint64 duration = player->duration();int seconds = position / 1000;int totalSeconds = duration / 1000;// 更新时间显示ui->timeLabel->setText(QString("%1:%2 / %3:%4").arg(seconds / 60, 2, 10, QLatin1Char('0')).arg(seconds % 60, 2, 10, QLatin1Char('0')).arg(totalSeconds / 60, 2, 10, QLatin1Char('0')).arg(totalSeconds % 60, 2, 10, QLatin1Char('0')));// 更新进度条int progress = (duration > 0) ? static_cast<int>(position * 100 / duration) : 0;ui->progressBar->setValue(progress);// 记录播放进度static int lastSecond = -1;if (seconds != lastSecond) {lastSecond = seconds;logMessage(QString("播放进度: %1% (%2/%3 秒)").arg(progress).arg(seconds).arg(totalSeconds));}}
}void MainWindow::handlePlayerStateChanged(QMediaPlayer::State state)
{switch (state) {case QMediaPlayer::StoppedState:logMessage("播放停止");ui->statusLabel->setText("播放完成");ui->playButton->setText("开始播放");progressTimer->stop();ui->progressBar->setValue(100);break;case QMediaPlayer::PlayingState:logMessage("播放进行中...");ui->statusLabel->setText("正在播放");ui->playButton->setText("停止播放");logMessage(QString("媒体时长: %1 毫秒").arg(player->duration()));break;case QMediaPlayer::PausedState:logMessage("播放暂停");ui->statusLabel->setText("播放暂停");ui->playButton->setText("继续播放");break;}
}void MainWindow::handlePlayerError(QMediaPlayer::Error error)
{QString errorMsg;switch (error) {case QMediaPlayer::NoError:return;case QMediaPlayer::ResourceError:errorMsg = "资源错误:无法访问媒体文件";break;case QMediaPlayer::FormatError:errorMsg = "格式错误:不支持的媒体格式";break;case QMediaPlayer::NetworkError:errorMsg = "网络错误";break;case QMediaPlayer::AccessDeniedError:errorMsg = "访问被拒绝:没有足够的权限";break;default:errorMsg = "未知错误";break;}logMessage(errorMsg);ui->statusLabel->setText("播放错误");ui->playButton->setText("开始播放");QMessageBox::warning(this, "播放错误", errorMsg);
}void MainWindow::logMessage(const QString &message)
{QString timestamp = QDateTime::currentDateTime().toString("hh:mm:ss");QString logEntry = QString("[%1] %2").arg(timestamp).arg(message);ui->logTextEdit->append(logEntry);qDebug() << logEntry;// 自动滚动到底部QTextCursor cursor = ui->logTextEdit->textCursor();cursor.movePosition(QTextCursor::End);ui->logTextEdit->setTextCursor(cursor);
}

4.mainwindow.ui文件

<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"><class>MainWindow</class><widget class="QMainWindow" name="MainWindow"><property name="geometry"><rect><x>0</x><y>0</y><width>600</width><height>500</height></rect></property><property name="minimumSize"><size><width>600</width><height>500</height></size></property><property name="windowTitle"><string>16K WAV音频播放器</string></property><widget class="QWidget" name="centralWidget"><layout class="QVBoxLayout" name="verticalLayout"><item><widget class="QLabel" name="titleLabel"><property name="text"><string>16K WAV音频播放器 (Qt5.14)</string></property><property name="alignment"><set>Qt::AlignCenter</set></property><property name="font"><font><pointsize>16</pointsize><bold>true</bold></font></property></widget></item><item><widget class="QLabel" name="filePathLabel"><property name="text"><string>文件路径显示</string></property><property name="frameShape"><enum>QFrame::Panel</enum></property><property name="frameShadow"><enum>QFrame::Sunken</enum></property><property name="wordWrap"><bool>true</bool></property></widget></item><item><widget class="QLabel" name="timeLabel"><property name="text"><string>00:00 / 00:00</string></property><property name="alignment"><set>Qt::AlignCenter</set></property><property name="font"><font><pointsize>18</pointsize><bold>true</bold></font></property></widget></item><item><widget class="QProgressBar" name="progressBar"><property name="value"><number>0</number></property><property name="textVisible"><bool>true</bool></property><property name="format"><string>%p%</string></property></widget></item><item><widget class="QPushButton" name="playButton"><property name="text"><string>开始播放</string></property><property name="minimumSize"><size><width>0</width><height>50</height></size></property><property name="styleSheet"><string>QPushButton {background-color: #4CAF50;color: white;font-weight: bold;font-size: 14px;border-radius: 5px;border: none;
}
QPushButton:hover {background-color: #45a049;
}
QPushButton:pressed {background-color: #3d8b40;
}
QPushButton:disabled {background-color: #cccccc;
}</string></property></widget></item><item><widget class="QLabel" name="statusLabel"><property name="text"><string>就绪</string></property><property name="alignment"><set>Qt::AlignCenter</set></property><property name="frameShape"><enum>QFrame::Box</enum></property><property name="font"><font><pointsize>10</pointsize><bold>true</bold></font></property></widget></item><item><widget class="QGroupBox" name="groupBox"><property name="title"><string>播放日志</string></property><layout class="QVBoxLayout" name="verticalLayout_2"><item><widget class="QTextEdit" name="logTextEdit"><property name="maximumHeight"><number>200</number></property><property name="readOnly"><bool>true</bool></property><property name="placeholderText"><string>播放日志将显示在这里...</string></property></widget></item></layout></widget></item></layout></widget></widget><resources/><connections/>
</ui>

四、显示效果

工程文件夹下需要有Output.wav,点击播放按钮则开始播放。


文章转载自:

http://MxvKSWI8.Ltpzr.cn
http://5Pyfd75t.Ltpzr.cn
http://GnirwC0X.Ltpzr.cn
http://ikwG8QsO.Ltpzr.cn
http://dhPh7nz2.Ltpzr.cn
http://TAjQLDs0.Ltpzr.cn
http://qonv7N65.Ltpzr.cn
http://kz3ab1Sa.Ltpzr.cn
http://fl9KKplG.Ltpzr.cn
http://4wKztfey.Ltpzr.cn
http://q5BGEO24.Ltpzr.cn
http://QwsB2YBA.Ltpzr.cn
http://fylaJCwq.Ltpzr.cn
http://ITRxkGyR.Ltpzr.cn
http://RmSiandO.Ltpzr.cn
http://sezZusKZ.Ltpzr.cn
http://DZpgY33f.Ltpzr.cn
http://IjK5Fwai.Ltpzr.cn
http://wIjXZWBz.Ltpzr.cn
http://ytAdtU3Q.Ltpzr.cn
http://1sv0mHYw.Ltpzr.cn
http://dtSWUsWc.Ltpzr.cn
http://4DzL1jMr.Ltpzr.cn
http://cOCldDLJ.Ltpzr.cn
http://1h0L4c83.Ltpzr.cn
http://PI0De2U1.Ltpzr.cn
http://t4gbS1V9.Ltpzr.cn
http://yfDkPbh9.Ltpzr.cn
http://ovW1cCxX.Ltpzr.cn
http://SdtbyWAS.Ltpzr.cn
http://www.dtcms.com/a/375887.html

相关文章:

  • 绿算技术闪耀智博会 赋能乡村振兴与产业升级
  • 差分数组(Difference Array)
  • 【硬核测评】格行ASR芯片+智能切网算法源码级解析(附高铁场景切换成功率99%方案)
  • 【git】首次clone的使用采用-b指定了分支,还使用了--depth=1 后续在这个基础上拉取所有的分支代码方法
  • AI时尚革命:Google Nano Banana如何颠覆传统穿搭创作
  • OpenCV 高阶 图像金字塔 用法解析及案例实现
  • 【系统分析师】第19章-关键技术:大数据处理系统分析与设计(核心总结)
  • Gears实测室:第一期·音游跨设备性能表现与工具价值实践
  • Next.js中服务器端渲染 (SSR) 详解:动态内容与 SEO 的完美结合
  • C++学习记录(7)vector
  • 【代码随想录算法训练营——Day7】哈希表——454.四数相加II、383.赎金信、15.三数之和、18.四数之和
  • IT 资产管理系统与 IT 服务管理:构建企业数字化的双引擎
  • 手搓Spring
  • LeetCode热题100--230. 二叉搜索树中第 K 小的元素--中等
  • element-plus表格默认展开有子的数据
  • 高带宽的L2 Cache的诀窍
  • 【嵌入式原理系列-第七篇】DMA:从原理到配置全解析
  • 最大异或对问题
  • Tess-two - Tess-two 文字识别(Tess-two 概述、Tess-two 文字识别、补充情况)
  • hot100 之移动零-283(双指针)
  • APP隐私合规评估测试核心要点与第三方APP检测全流程解析
  • ARM汇编与栈操作指南
  • 在 Keil 中将 STM32 工程下载到 RAM 进行调试运行
  • 高效数据操作:详解MySQL UPDATE中的CASE条件更新与性能优化
  • 构建企业级Selenium爬虫:基于隧道代理的IP管理架构
  • Nginx限流与防爬虫与安全配置方案
  • YOLO11训练自己数据集的注意事项、技巧
  • Kafka面试精讲 Day 13:故障检测与自动恢复
  • Linux学习——管理网络安全(二十一)
  • 平衡车 -- PID