c++在线音乐播放器项目开发记录(2)

前言

因为放寒假了,时间比较短,想找实习也不好找,干脆在家加强一下技术栈,首先从c++学起,最适合练手的就是qt的项目了,我是根据B站视频【5个C/C++硬核简历项目实战,可直接写入简历,包含:Qt项目、音视频流媒体开发、后端开发、DPDK网络编程、KV存储、Linux内核。总有一个实战项目适合你!】来进行学习的,这篇文章主要是记录一下在跟视频做的过程中,自己的学习体会和问题的解决思路。

项目已上传至Github:https://github.com/MengFanjun020906/OnlineMusic

1.主窗口添加功能

1.1 进度条控件美化

 // 播放进度条控件美化
    ui->horizontalSlider_PlayProgress->setStyleSheet("QSlider::groove:horizontal {"
                                                     "    border: 1px solid #bbb;"
                                                     "    background: white;"
                                                     "    height: 10px;"
                                                     "    border-radius: 5px;"
                                                     "}"
                                                     "QSlider::sub-page:horizontal {"
                                                     "    background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #66e, stop: 1 #bbf);"
                                                     "    border: 1px solid #777;"
                                                     "    height: 10px;"
                                                     "    border-radius: 5px;"
                                                     "}"
                                                     "QSlider::add-page:horizontal {"
                                                     "    background: #fff;"
                                                     "    border: 1px solid #777;"
                                                     "    height: 10px;"
                                                     "    border-radius: 5px;"
                                                     "}"
                                                     "QSlider::handle:horizontal {"
                                                     "    background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #eee, stop:1 #ccc);"
                                                     "    border: 1px solid #777;"
                                                     "    width: 18px;"
                                                     "    margin-top: -4px;"
                                                     "    margin-bottom: -4px;"
                                                     "    border-radius: 9px;"
                                                     "}");


    ui->horizontalSlider_Volume->setStyleSheet("QSlider::groove:horizontal {"
                                                     "    border: 1px solid #bbb;"
                                                     "    background: white;"
                                                     "    height: 10px;"
                                                     "    border-radius: 5px;"
                                                     "}"
                                                     "QSlider::sub-page:horizontal {"
                                                     "    background: qlineargradient(x1: 0, y1: 0, x2: 0, y2: 1, stop: 0 #66e, stop: 1 #bbf);"
                                                     "    border: 1px solid #777;"
                                                     "    height: 10px;"
                                                     "    border-radius: 5px;"
                                                     "}"
                                                     "QSlider::add-page:horizontal {"
                                                     "    background: #fff;"
                                                     "    border: 1px solid #777;"
                                                     "    height: 10px;"
                                                     "    border-radius: 5px;"
                                                     "}"
                                                     "QSlider::handle:horizontal {"
                                                     "    background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #eee, stop:1 #ccc);"
                                                     "    border: 1px solid #777;"
                                                     "    width: 18px;"
                                                     "    margin-top: -4px;"
                                                     "    margin-bottom: -4px;"
                                                     "    border-radius: 9px;"
                                                     "}");

实现的效果如下,虽然也不是特别好看,但是效果比原来的好看得多。
在这里插入图片描述

1.2 初始化多媒体实例

因为qt6的MediaPlayList被移除了,所以需要我们自己写playlist的相关函数和头文件,但如果是qt5的话,这个类就可以正常使用

    //将光标焦点定位到搜索歌曲名称的控件
    ui->lineEdit_InputSong->setFocus();

    //初始化
    NetworkAccessManager = new QNetworkAccessManager(this);

    iPos=0;

    //初始文本对象
    docTextObject = ui->plainTextEdit_SongList->document();

    //将控件设置为只读
    ui->plainTextEdit_SongList->setReadOnly(true);

    //初始化多媒体实例
    p_PlayerObject=new QMediaPlayer(this);
    //p_PlayerList = new
    Playlist *p_PlayList = new Playlist(this);

    //设置播放模式
    p_PlayList->setPlaybackMode(Playlist::Loop);

    //信号与槽处理如下
    connect(p_PlayerObject,SIGNAL(positionChanged(qint64)),this,SLOT(HandleLCDNumberTimeChangeFunc(qint64)));
    connect(p_PlayerObject,SIGNAL(positionChanged(qint64)),this,SLOT(HandlePositionChangeFunc(qint64)));
    connect(p_PlayerObject,SIGNAL(positionChanged(qint64)),this,SLOT(HandleProgressTimeChangeFunc(qint64)));
    connect(NetworkAccessManager,SIGNAL(finished(QNetworkReply*)),this,SLOT(HandleDataBackFunc(QNetworkReply*)));

2.搜索歌曲显示歌手功能

这个函数是 OnlineMusicWidget 类的一个槽函数,它会在 pushButton_SearchSong 按钮被点击时触发。其主要功能是根据用户在 lineEdit_InputSong 输入框中输入的歌曲名称,向网易云音乐的搜索 API 发送一个 GET 请求,以获取相关歌曲的搜索结果。

void OnlineMusicWidget::HandleDataBackFunc(QNetworkReply *pReply)
{
    //读取网络回款数据
    QByteArySearchInfo = pReply->readAll();

    QJsonParseError JSonPError;//定义错误信息对象

    //将json文本转换为json文件对象
    QJsonDocument JSonDoc_RecvData=QJsonDocument::fromJson(QByteArySearchInfo,&JSonPError);
    if(JSonPError.error!=QJsonParseError::NoError)//判断是否符合规则
    {
        QMessageBox::critical(this,"Prompt","提示:获取歌曲json出错,请重新检查",QMessageBox::Yes);
        return;
    }
    //QJsonObject使用函数object();
    QJsonObject TotalJsonObject = JSonDoc_RecvData.object();

    //列出json里面的所有key
    QStringList strKeys=TotalJsonObject.keys();

    if(strKeys.contains("result"))//与数据信息
    {
        //将带有result的数据内容提取之后转换为对象
        QJsonObject resultobject=TotalJsonObject["result"].toObject();

        //存储所有keys
        QStringList strResultKeys=resultobject.keys();

        if(strResultKeys.contains("songs"))
        {
            QJsonArray array=resultobject["songs"].toArray();

            //通过for循环查找歌曲当中的字段信息
            for(auto isong:array)
            {
                QJsonObject jsonobject1 = isong.toObject();
                //获取歌曲ID 歌名 歌手
                I_MusicID = jsonobject1["id"].toInt();
                StrMusicName = jsonobject1["name"].toString();


                QStringList strkeys = jsonobject1.keys();

                if(strkeys.contains("artists"))
                {
                    QJsonArray artitstsjsonarray= jsonobject1["artists"].toArray();
                    for(auto js:artitstsjsonarray)
                    {
                        QJsonObject jsonobject2=js.toObject();
                        StrSingerName = jsonobject2["name"].toString();
                    }
                }
            }
        }

    }
    // 生成歌曲 URL
    QString url = QString("https://music.163.com/song/media/outer/url?id=%0").arg(I_MusicID);

    // 创建一个 QVariantMap 并将歌曲 URL 存储在 "path" 键下
    QVariantMap song;
    song["path"] = url;
    // 调用 appendSong 函数将歌曲添加到播放列表
    p_PlayList->appendSong(song);

    ui->plainTextEdit_SongList->appendPlainText(StrMusicName+"-"+StrSingerName);
}
//搜索歌曲名称实现
void OnlineMusicWidget::on_pushButton_SearchSong_clicked()
{
    QString str1,str2;
    str1=ui->lineEdit_InputSong->text();


    str2="http://music.163.com/api/search/get/web?csrf_token=hlpretag=&hlposttag=&s={"+str1+"}&type=1&offset=0&total=true&limit=1";

    //定义一个请求对象
    QNetworkRequest networkRequest;
    networkRequest.setUrl(str2);

    //将请求格式设置给对应请求对象
    networkRequest.setUrl(str2);
    //使用QNetworkAccessManager类对应的API发送GET请求并获取响应数据



    NetworkAccessManager->get(networkRequest);

}

在这里插入图片描述

3.播放功能

3.1 播放按钮播放

从回传的id去获取歌曲的url,但是需要注意的是,VIP歌曲不能播放,网易云的网页版和APP版还不一样,网页版连试听都没有,我再搜岁歌曲的时候,发现怎么着都播放不出来,选几首比较冷门的歌,才发现原来问题是没有开vip。

//播放歌曲
void OnlineMusicWidget::on_pushButton_PlaySong_clicked()
{




    qDebug() << "播放列表内容:" << playList;
    qDebug() << "当前播放索引:" << currentIndex;
    qDebug() << "播放器状态:" << p_PlayerObject->playbackState();
    qDebug() << "[Debug] 当前播放器状态:" << p_PlayerObject->playbackState();

    // 1. 处理空播放列表
    if (playList.isEmpty()) {
        QMessageBox::warning(this, "错误", "播放列表为空");
        return;
    }

    // 2. 自动定位到第一首
    if (currentIndex == -1) {
        currentIndex = 0;
    }

    // 3. 核心逻辑
    switch (p_PlayerObject->playbackState()) {
    case QMediaPlayer::StoppedState:  // 停止状态
    case QMediaPlayer::PausedState:   // 暂停状态
        // 只有源文件变化时才重新设置
        if (p_PlayerObject->source() != playList[currentIndex]) {
            p_PlayerObject->setSource(playList[currentIndex]);
        }
        p_PlayerObject->play();
        //ui->pushButton_PlaySong->setText("暂停");
        break;

    case QMediaPlayer::PlayingState:  // 正在播放
        p_PlayerObject->pause();
        //ui->pushButton_PlaySong->setText("播放");
        break;

    default:  // 无媒体或错误状态
        p_PlayerObject->setSource(playList[currentIndex]);
        p_PlayerObject->play();
        //ui->pushButton_PlaySong->setText("暂停");
        break;
    }
}

3.2 暂停与停止功能

这里直接调用PlayerObject的函数即可

//暂停播放
void OnlineMusicWidget::on_pushButton_PauseSong_clicked()
{
    // 只有正在播放时才能暂停
    if (p_PlayerObject->playbackState() == QMediaPlayer::PlayingState) {
        p_PlayerObject->pause();
        //ui->pushButton_PlaySong->setText("播放"); // 同步更新播放按钮状态
        qDebug() << "音乐已暂停";
    }
}

//停止播放
void OnlineMusicWidget::on_pushButton_StopPlaySong_clicked()
{
    if (p_PlayerObject->playbackState() != QMediaPlayer::StoppedState) {
        p_PlayerObject->stop();
        //ui->pushButton_PlaySong->setText("播放");  // 强制更新播放按钮状态
        qDebug() << "音乐已停止";
    }
}

3.3 上一曲与下一曲的切换

//播放上一曲
void OnlineMusicWidget::on_pushButton_PreviousSong_clicked()
{

    if (playList.isEmpty()) {
        QMessageBox::warning(this, "提示", "播放列表为空");
        return;
    }


    // 计算新索引(支持循环)
    currentIndex = (currentIndex - 1 + playList.size()) % playList.size();

    // 设置新播放源
    p_PlayerObject->setSource(playList[currentIndex]);

    // 自动开始播放
    p_PlayerObject->play();
    qDebug() << "上一曲";


}
//播放下一曲
void OnlineMusicWidget::on_pushButton_NextSong_2_clicked()
{
    if (playList.isEmpty()) {
        QMessageBox::warning(this, "提示", "播放列表为空");
        return;
    }

    // 计算新索引(支持循环)
    currentIndex = (currentIndex + 1) % playList.size();

    // 设置新播放源
    p_PlayerObject->setSource(playList[currentIndex]);

    // 自动开始播放
    p_PlayerObject->play();
    qDebug() << "下一曲";

}

4.音量控制

静音实现

void OnlineMusicWidget::on_pushButton_SoundYesNo_clicked()
{
    QAudioOutput* audioOutput = p_PlayerObject->audioOutput();

    if (isMuted) {
        // 取消静音,恢复之前音量
        audioOutput->setMuted(false);
        audioOutput->setVolume(previousVolume);
        ui->horizontalSlider_Volume->setValue(previousVolume * 100);
        ui->pushButton_SoundYesNo->setIcon(QIcon(":/new/prefix1/Images/MSound.png"));
        qDebug() << "取消静音,恢复音量到:" << previousVolume;
    } else {
        // 记录当前音量并静音
        previousVolume = audioOutput->volume();
        audioOutput->setMuted(true);
        ui->pushButton_SoundYesNo->setIcon(QIcon(":/new/prefix1/Images/MNoSound.png"));
        qDebug() << "静音,原音量:" << previousVolume;
    }

    isMuted = !isMuted;  // 切换状态

}

拖动滑块改变歌曲音量

//音量控制
void OnlineMusicWidget::on_horizontalSlider_Volume_valueChanged(int value)
{
    QAudioOutput* audioOutput = p_PlayerObject->audioOutput();

    // 将滑块值(0-100)转换为浮点音量(0.0-1.0)
    qreal volume = qBound(0.0, value / 100.0, 1.0);
    audioOutput->setVolume(volume);

    // 同步静音状态
    if (volume > 0 && audioOutput->isMuted()) {
        audioOutput->setMuted(false);
        ui->pushButton_SoundYesNo->setIcon(QIcon(":/new/prefix1/Images/MSound.png"));
        isMuted = false;
    }


}

5.歌曲时间显示

在进度条右侧的LCD数字会显示歌曲的时长

//处理LCD控件时间变化
void OnlineMusicWidget::HandleLCDNumberTimeChangeFunc(qint64 duration)
{
    int int_Second=duration/1000;
    int int_Minute=int_Second/60;
    int_Second=int_Second%60;
    QString strSongTime=QString::asprintf("%d:%d",int_Minute,int_Second);
    ui->lcdNumber_PlayTime->display(strSongTime);
}

歌曲的进度条会随着播放而变化

// 处理进度条控件变化
void OnlineMusicWidget::HandleProgressTimeChangeFunc(qint64 duration)
{
    //设置进度条最大值
    ui->horizontalSlider_PlayProgress->setMaximum(duration);
}

在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/962673.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

PyQt6医疗多模态大语言模型(MLLM)实用系统框架构建初探(下.代码部分)

医疗 MLLM 框架编程实现 本医疗 MLLM 框架结合 Python 与 PyQt6 构建,旨在实现多模态医疗数据融合分析并提供可视化界面。下面从数据预处理、模型构建与训练、可视化界面开发、模型 - 界面通信与部署这几个关键部分详细介绍编程实现。 6.1 数据预处理 在医疗 MLLM 框架中,多…

【项目初始化】

项目初始化 使用脚手架创建项目Vite创建项目推荐拓展 使用脚手架创建项目 Vite Vite 是一个现代的前端构建工具&#xff0c;它提供了极速的更新和开发体验&#xff0c;支持多种前端框架&#xff0c;如 Vue、React 等创建项目 pnpm create vuelatest推荐拓展

云原生(五十二) | DataGrip软件使用

文章目录 DataGrip软件使用 一、DataGrip基本使用 二、软件界面介绍 三、附件文件夹到项目中 四、DataGrip设置 五、SQL执行快捷键 DataGrip软件使用 一、DataGrip基本使用 1. 软件界面介绍 2. 附加文件夹到项目中【重要】 3. DataGrip配置 快捷键使用&#xff1a;C…

爬虫基础(二)Web网页的基本原理

一、网页的组成 网页由三部分构成&#xff1a;HTML、JavaScript、CSS。 &#xff08;1&#xff09;HTML HTML 相当于网页的骨架&#xff0c;它通过使用标签来定义网页内容的结构。 举个例子&#xff1a; 它把图片标签为img、把视频标签为video&#xff0c;然后组合到一个界面…

【MySQL】MySQL客户端连接用 localhost和127.0.0.1的区别

# systemctl status mysqld # ss -tan | grep 3306 # mysql -V localhost与127.0.0.1的区别是什么&#xff1f; 相信有人会说是本地IP&#xff0c;曾有人说&#xff0c;用127.0.0.1比localhost好&#xff0c;可以减少一次解析。 看来这个入门问题还有人不清楚&#xff0c;其实…

【算法设计与分析】实验3:动态规划—最长公共子序列

目录 一、实验目的 二、实验环境 三、实验内容 四、核心代码 五、记录与处理 六、思考与总结 七、完整报告和成果文件提取链接 一、实验目的 掌握动态规划求解问题的思想&#xff1b;针对不同的问题&#xff0c;会利用动态规划进行设计求解以及时间复杂度分析&#xff0…

FIDL:Flutter与原生通讯的新姿势,不局限于基础数据类型

void initUser(User user); } 2、执行命令./gradlew assembleDebug&#xff0c;生成IUserServiceStub类和fidl.json文件 3、打开通道&#xff0c;向Flutter公开方法 FidlChannel.openChannel(getFlutterEngine().getDartExecutor(), new IUserServiceStub() { Override void…

JavaScript闭包深入剖析:性能剖析与优化技巧

一、引言 在 JavaScript 的奇妙世界里&#xff0c;闭包无疑是一个既强大又迷人的特性。它就像是一把万能钥匙&#xff0c;为开发者打开了实现各种高级功能的大门。从数据封装与保护&#xff0c;到函数的记忆化&#xff0c;再到模块化开发&#xff0c;闭包都发挥着举足轻重的作…

AnyThingLLM本地私有知识库搭建

***************************************************** 环境准备 操作系统&#xff1a;Windows11 内存&#xff1a;32GB RAM 存储&#xff1a;预留 300GB 可用空间 显存: 16G 网络: 100M带宽 前置准备: 已安装ollama环境 deepseek本地大模型 ***************************…

C语言指针专题四 -- 多级指针

目录 1. 多级指针的核心原理 1. 多级指针的定义 2. 内存结构示意图 3. 多级指针的用途 2. 编程实例 实例1&#xff1a;二级指针操作&#xff08;修改一级指针的值&#xff09; 实例2&#xff1a;动态二维数组&#xff08;二级指针&#xff09; 实例3&#xff1a;三级指…

【Wordpress网站制作】切换语言的问题

前言 自学笔记&#xff0c;解决问题为主&#xff0c;欢迎补充。 本文重点&#xff1a;如何将页面语言从默认的【英语】修改成【中文】。 问题描述 安装完wordpress&#xff0c;在【Setting】→【General】的语言中&#xff0c;选项只有英语。无法切换成中文 方法1: 在 wp-c…

使用openwrt搭建ipsec隧道

背景&#xff1a;最近同事遇到了个ipsec问题&#xff0c;做的ipsec特性&#xff0c;ftp下载ipv6性能只有100kb, 正面定位该问题也蛮久了&#xff0c;项目没有用openwrt, 不过用了开源组件strongswan, 加密算法这些也是内核自带的&#xff0c;想着开源的不太可能有问题&#xff…

对比DeepSeek、ChatGPT和Kimi的学术写作撰写引言能力

引言 引言部分引入研究主题&#xff0c;明确研究背景、问题陈述&#xff0c;并提出研究的目的和重要性&#xff0c;最后&#xff0c;概述研究方法和论文结构。 下面我们使用DeepSeek、ChatGPT4以及Kimi辅助引言撰写。 提示词&#xff1a; 你现在是一名[计算机理论专家]&#…

实测数据处理(Wk算法处理)——SAR成像算法系列(十二)

系列文章目录 《SAR学习笔记-SAR成像算法系列&#xff08;一&#xff09;》 《wk算法-SAR成像算法系列&#xff08;五&#xff09;》 文章目录 前言 一、算法流程 1.1、回波信号生成 2.2 Stolt插值 2.3 距离脉冲压缩 2.4 方位脉冲压缩 2.5 SAR成像 二、仿真实验 2.1、仿真参数…

基于遗传优化GRNN和Hog特征提取的交通标志识别算法matlab仿真

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 4.1 HOG 4.2 GRNN&#xff08;General Regression Neural Network&#xff09;模型原理 4.3 遗传算法&#xff08;GA&#xff09;优化GRNN平滑因子 5.算法完整程序工程 1.算法运行效果图预…

【Numpy核心编程攻略:Python数据处理、分析详解与科学计算】1.18 逻辑运算引擎:数组条件判断的智能法则

1.18 逻辑运算引擎&#xff1a;数组条件判断的智能法则 1.18.1 目录 #mermaid-svg-QAFjJvNdJ5P4IVbV {font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}#mermaid-svg-QAFjJvNdJ5P4IVbV .error-icon{fill:#552222;}#mermaid-svg-QAF…

基于Python的药物相互作用预测模型AI构建与优化(上.文字部分)

一、引言 1.1 研究背景与意义 在临床用药过程中,药物相互作用(Drug - Drug Interaction, DDI)是一个不可忽视的重要问题。当患者同时服用两种或两种以上药物时,药物之间可能会发生相互作用,从而改变药物的疗效、增加不良反应的发生风险,甚至危及患者的生命安全。例如,…

基于Spring Security 6的OAuth2 系列之八 - 授权服务器--Spring Authrization Server的基本原理

之所以想写这一系列&#xff0c;是因为之前工作过程中使用Spring Security OAuth2搭建了网关和授权服务器&#xff0c;但当时基于spring-boot 2.3.x&#xff0c;其默认的Spring Security是5.3.x。之后新项目升级到了spring-boot 3.3.0&#xff0c;结果一看Spring Security也升级…

STC32通用GPIO中断,库函数配置方式 AI8051U和STC32G已测试没有问题

近来STC的单片机已经出到32位了&#xff0c;并且个人自己打板测试了几个型号&#xff0c;相比之前的51完全不是一个量级&#xff0c;可以通过以下这张图片中的信息来感受一下如今的32位8051单片机的强大&#xff0c;也是很很期待25年的这一新作了&#xff01; 配图为AI8052U或…

Git进阶之旅:Git Hub注册创建仓库

介绍&#xff1a; GitHub 是一个面向开源及私有软件项目的托管平台&#xff0c;因为只支持 git 作为唯一的版本库格式进行托管&#xff0c;故名 GitHub 仓库注册&#xff1a; GitHub官网&#xff1a;https://github.com/ 修改本地仓库用户名&#xff1a; git config --local…