《二十二》Qt 音频编程实战---做一个音频播放器

news2024/11/26 4:48:54

1.UI界面制作

        作为一个音乐播放器,最基础的肯定就是播放、暂停、上一首以及下一首,为了使这个界面好看一点,还加入了音量控制、进度条、歌曲列表等内容,至于这种配色和效果好不好看,我也不知道,个人审美一如既往的不达标。

QT设计界面有两种方式,一种是直接通过纯代码的方式实现,将各种控件以及布局通过代码的方式编排成一个完整的UI界面,但是这种方式较为麻烦也比较复杂,代码量也比较大,还有一种就是通过UI文件拖拽QT控件,来对整个布局进行排版的效果,我这里为了省事采用的就是这种方式,至于实际效果怎么样那就要看个人审美了。

整个UI界面内部使用到的基础控件有以下几种:

控件名称       

控件类控件功能
PushButtonQPushButton 用来控制添加、删除、清空歌曲列表的功能
horizontalSliderQSlider用来控制播放进度、音量等功能
listWidgetQListWidget歌单列表,内部存入添加的歌曲
groupBox  QgroupBox内部放入播放列表
label Qlabel  标签,可以用来显示提示信息以及图片

2.加入播放器类

UI界面设计完成之后就是加入播放器类。QT中使用播放器类需要加入对应的链接模块,通过查询QT的帮助手册可以查到,然后在项目的pro文件中加上即可。

加入链接模块后,需要添加我们需要使用到的一些相关的播放器类头文件 

#include<QMediaPlayer>
#include<QMediaPlaylist>
#include<QFileDialog>

3.播放器初始化

首先在头文件先定义出我们所需要的成员以及槽函数,定义一个QMediaPlayer类以及QMediaPlaylist类,还需要记录歌曲时长,以及位置,方便我们拖动进度条。

QMediaPlaylist类,可以为QMediaPlayer提供一个播放列表,它其实是QMediaContent对象的列表,QMediaPlayer通过函数setPlaylist来设置一个播放列表。QMediaPlaylist通过函数addMedia向播放列表添加一个媒体文件。QMediaplaylist类的播放模式:PlaybackMode

private:
    Ui::MainWindow *ui;

    QMediaPlayer *player;
    QMediaPlaylist *playlist;

    QString drtTime;//歌曲时长
    QString pstTime;//播放位置

private slots:
    void Onstatechg(QMediaPlayer::State state);//按钮切换状态
    void Onplaylishchg(int pos);//播放列表
    void OnDrtchg(qint64 drt);//歌曲总时间长度
    void Onpstchg(qint64 pos);//播放歌曲当前位置

对于槽函数Onstatechg()的实现,我们对state状态进行比较,从而对按钮:播放,暂停,停止按钮进行处理。

void MainWindow::Onstatechg(QMediaPlayer::State state)//按钮切换状态
{
    ui->pushButton_player->setEnabled(!(state==QMediaPlayer::PlayingState));
    ui->pushButton_puse->setEnabled(state==QMediaPlayer::PlayingState);
    ui->pushButton_stop->setEnabled(state==QMediaPlayer::PlayingState);
}
槽函数Onplaylishchg() 的实现,获取listWidget中的项目,来显示到下方歌曲名称的label中
void MainWindow::Onplaylishchg(int pos)//播放列表
{
    ui->listWidget->setCurrentRow(pos);
    QListWidgetItem *item=ui->listWidget->currentItem();
    if(item){
        ui->label_name->setText(item->text());
    }
}

槽函数OnDrtchg()的实现,先获取进度条的最大长度,根据获取的歌曲时间,转化成分,秒。放到歌曲时间label中

void MainWindow::OnDrtchg(qint64 drt)//歌曲总时间长度
{
    ui->horizontalSlider_speed->setMaximum(drt);
    int sec=drt/1000;//总共多少秒
    int min=sec/60;//分
    sec=sec%60;//秒

    drtTime=QString::asprintf("%d:%d",min,sec);
    ui->label_time->setText(pstTime+"/"+drtTime);
}

调整进度条,Onpstchg() 与上面方法类似,目的就是更新位置

void MainWindow::Onpstchg(qint64 pos)//播放歌曲当前位置,更新变化
{
    if(ui->horizontalSlider_speed->isSliderDown()){
        return;
    }
    ui->horizontalSlider_speed->setSliderPosition(pos);

    int sec=pos/1000;
    int min=sec/60;
    sec=sec%60;

    pstTime=QString::asprintf("%d:%d",min,sec);
    ui->label_time->setText(pstTime+"/"+drtTime);
}

接着就是槽函数链接了:

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    player=new QMediaPlayer(this);
    playlist=new QMediaPlaylist(this);

    playlist->setPlaybackMode(QMediaPlaylist::Loop);//循环模式
    player->setPlaylist(playlist);

    connect(player,SIGNAL(stateChanged(QMediaPlayer::State)),this,SLOT(Onstatechg(QMediaPlayer::State)));
    connect(player,SIGNAL(positionChanged(qint64)),this,SLOT(Onpstchg(qint64 )));
    connect(player,SIGNAL(durationChanged(qint64)),this,SLOT(OnDrtchg(qint64 )));
    connect(playlist,SIGNAL(currentIndexChanged(int)),this,SLOT(Onplaylishchg(int)));
}

4.功能控件

再接着我们来实现各种按钮以及拖动进度条事件的槽函数:

这些都是我们要实现的槽函数:

先从打开文件开始:

void MainWindow::on_pushButton_open_clicked()
{
    //添加歌曲
    QString currentpath=QDir::homePath();//当前位置
    QString dlgtitle="请选择音频文件:";//文件对话框标题
    QString strfilter="所有文件(*.*);;音频文件(*.mp3);;mp3文件(*.mp3)";//文件过滤器
    QStringList filelist=QFileDialog::getOpenFileNames(this,dlgtitle,currentpath,strfilter);
    if(filelist.count()<1){
        return;
    }
    for(int i=0;i<filelist.count();i++){
        QString afile=filelist.at(i);
        playlist->addMedia(QUrl::fromLocalFile(afile));//添加文件

        QFileInfo fileinfo(afile);
        ui->listWidget->addItem(fileinfo.fileName());//将文件添加到界面listwidget控件
    }
    if(player->state()!=QMediaPlayer::PlayingState){
        playlist->setCurrentIndex(0);
    }
    player->play();
}

首先要获取到位置,通过文件过滤来找到我们所需要的mp3文件,根据选中的文件数量依次添加到listWidget中,

剩下的 就比较简单了,我们全放出来:

void MainWindow::on_pushButton_player_clicked()
{
    if(playlist->currentIndex()<0){
        playlist->setCurrentIndex(0);
    }
    player->play();
}

void MainWindow::on_pushButton_puse_clicked()
{
    player->pause();
}

void MainWindow::on_pushButton_stop_clicked()
{
    player->stop();
}

void MainWindow::on_pushButton_prev_clicked()
{
    playlist->previous();
}

void MainWindow::on_pushButton_next_clicked()
{
    playlist->next();
}

void MainWindow::on_pushButton_volumn_clicked()
{
    bool mutex=player->isMuted();
    player->setMuted(!mutex);
    if(mutex){
        ui->pushButton_volumn->setIcon(QIcon(":/icon/sound.png"));
    }else{
        ui->pushButton_volumn->setIcon(QIcon(":/icon/mute.png"));
    }
}


void MainWindow::on_horizontalSlider_Volumn_valueChanged(int value)
{
    player->setVolume(value);
}

void MainWindow::on_horizontalSlider_speed_valueChanged(int value)
{
    player->setPosition(value);
}

以及图标我们可以创建一个资源文件,来放图标:

后续在ui文件中导入:

 

5. 总结

        到这里基本是一个简单的音乐播放器就基本实现了,虽然里面有很多功能写的不是很详细,也有一部分操作我没有做,但是基本能实现播放、暂停、切换等基本功能。

        如果后期需要对播放器的功能进行添加可以自行添加,比方说,QT有自带的视频播放功能,可以将中间的GIF图片换成播放歌曲的MV,还可以添加一个comboBox控件来选择当前播放器的播放模式,QT有内置的宏可以直接设置,我这里是直接选择的循环播放。

        还有就是好像可以实现从网络获取歌曲的方法,这种的话就可以不用提前下载好歌曲了,大家可以自己去找一下,不要问我为什么没做这种,问就是我是菜鸡,我不会。

        好了,差不多到这里也要结束了,作为一个QT的初学者,里面有很多设置方法在各位大佬看来可能很笨,但是目前就只有这种水平了,而且大家如果对各种基础控件的样式不满意,可以去自己找一下各种样式表,自己设置一下,我这里就没有做太多这种操作了。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

C语言初阶(6) - 指针

目录 1.指针是什么&#xff1f; 2. 指针和指针类型 2.1 指针 - 整数 2.2 指针的解引用 3. 野指针 3.1 野指针成因 3.2 如何规避野指针 4. 常量指针和指针常量 (const) 4.1.常量指针 4.2.指针常量 5. 指针运算 5.1 指针-整数 5.2 指针-指针 5.3指针的关系运算 6.…

离线使用evaluate

一、目录 步骤demorouge-n 含义 二、实现 步骤 离线使用evaluate: 1. 下载evaluate 文件&#xff1a;https://github.com/huggingface/evaluate/tree/main2. 离线使用 路径/evaluate-main/metrics/rougedemo import evaluate离线使用evaluate: 1. 下载evaluate 文件&…

Android 百度语音识别(详细步骤+源码),京东android面试题

改好之后&#xff0c;请注意&#xff0c;每个人都是不一样&#xff0c;你如果发现你创建的应用的配置的值和我创建的是一模一样的&#xff0c;你马上去百度提BUG&#xff0c;他们的程序员要就要下岗了~ OK&#xff0c;现在配置也完成了&#xff0c;接下来就是使用了。 ③ 使用…

五一超级课堂---Llama3-Tutorial(Llama 3 超级课堂)---第四节Llama 3 高效部署实践(LMDeploy 版)

课程文档&#xff1a; https://github.com/SmartFlowAI/Llama3-Tutorial 课程视频&#xff1a; https://space.bilibili.com/3546636263360696/channel/collectiondetail?sid2892740&spm_id_from333.788.0.0 操作平台&#xff1a; https://studio.intern-ai.org.cn/consol…

浅谈现代消息队列与云存储

一、前言 1970 年代末&#xff0c;消息系统用于管理多主机的打印作业&#xff0c;这种削峰解耦的能力逐渐被标准化为“点对点模型”和稍复杂的“发布订阅模型”&#xff0c;实现了数据处理的分布式协同。随着时代的发展&#xff0c;Kafka&#xff0c;Amazon SQS&#xff0c;Ro…

charts3D地球--添加航线

要在地球视角下画出海运路线图 方案 添加 globl 地球创建geo地理坐标系创建canvas对象用于承载地图世界地图this.worldChart//初始化canvas节点let cav = document.createElement("canvas");this.$echarts.registerMap("world", geoJson);this.worldChart…

AVL树的原理及其实现

文章目录 前言了解AVL树AVL树的特点AVL树的节点调整方案右单旋为什么要右单旋呢&#xff1f;右单旋代码 左单旋为什么要左单旋&#xff1f;左单旋代码 左右双旋左右双旋之后平衡因子的情况左右双旋代码实现 右左双旋右左双旋代码&#xff1a; 简单测试 前言 回顾我们对于二叉搜…

保研面试408复习 4——操作系统、计网

文章目录 1、操作系统一、文件系统中文件是如何组织的&#xff1f;二、文件的整体概述三、UNIX外存空闲空间管理 2、计算机网络一、CSMA/CD 协议&#xff08;数据链路层协议&#xff09;二、以太网MAC帧MTU 标记文字记忆&#xff0c;加粗文字注意&#xff0c;普通文字理解。 1、…

值得推荐的10+REST API测试工具

什么是API&#xff1f; API是一个软件解决方案&#xff0c;作为中介&#xff0c;使两个应用程序能够相互交互。以下一些特征让API变得更加有用和有价值&#xff1a; 遵守REST和HTTP等易于访问、广泛理解和开发人员友好的标准。API不仅仅是几行代码&#xff1b;这些是为移动开…

qml 和 c++类的数据交互

1、 新建一个需要交互的C++类 1)添加QObject头文件 2)添加自QObject的继承 3)添加Q_OBJECT宏 4)使用Q_PROPERTY,定义两个交互的属性,并设置读写的方法和变更属性的信号。 5)添加方法、槽函数和变量 2、在main.cpp中添加实例化对象的QML上下文 1)添加需要QML交互的…

Kubernetes学习-集群搭建篇(一) 搭建Master结点

&#x1f3f7;️个人主页&#xff1a;牵着猫散步的鼠鼠 &#x1f3f7;️系列专栏&#xff1a;Kubernetes渐进式学习-专栏 &#x1f3f7;️个人学习笔记&#xff0c;若有缺误&#xff0c;欢迎评论区指正 目录 1. 前言 2. 集群搭建方式 3. 环境说明 4. 利用kubeadm初始化Ma…

应该在哪里找海外ip代理?

出于学习工作&#xff0c;或者游戏娱乐的需求&#xff0c;许多人需要使用海外代理ip。那么我们该如何寻找到合适的、正规的、安全的海外代理ip呢&#xff1f; 首先&#xff0c;我们需要明白使用海外IP代理可能带来的风险&#xff0c;包括隐私泄露、网络速度变慢、安全风险以及可…

百融云创回购计划加速落实 机构看好中长期吸引力

单日回购近400万港元B类股份&#xff0c;一站式服务的AI科技领航者百融云创&#xff08;百融云-W,6608.HK&#xff09;的回购计划正在加速落实。 此前&#xff0c;在百融云创2023年年度业绩公告的同时&#xff0c;该公司一并披露将在2024年不时在公开市场购回总金额不超过2.5亿…

原生微信小程序canvas签名功能

半个月前百度搜出来的&#xff0c;没存书签现在不知道是哪篇文章了&#xff0c;再搜也没搜出来那篇文章&#xff0c;还好当时把代码复制到本地跑了一下&#xff0c;现在再发csdn存一下。 sign.js Page({data: {ctx: null,width: null,height: null,drawCount: 0,drawState: &…

WebStorm开发插件

WebStorm开发插件 开发 WebStorm 插件是一项令人兴奋的任务&#xff0c;它可以帮助提升开发效率&#xff0c;定制 IDE 来满足个人或团队的需求。在这份指南中&#xff0c;我将向你介绍如何开始开发 WebStorm 插件&#xff0c;并提供一些实用的技巧和建议。 1. 准备工作 在开…

“幽灵“再临!新型攻击瞄准英特尔CPU;微软Outlook漏洞被俄利用,网络间谍攻击捷克德国实体 | 安全周报0510

1. 微软Outlook漏洞被俄罗斯APT28利用&#xff0c;捷克德国实体遭网络间谍攻击&#xff01; 捷克和德国于周五透露&#xff0c;他们成为与俄罗斯有关的APT28组织进行的长期网络间谍活动的目标&#xff0c;此举遭到欧洲联盟&#xff08;E.U.&#xff09;、北大西洋公约组织&…

视频拼接融合产品的产品与架构设计(二)

视频拼接融合产品的产品与架构设计一 以上是第一期&#xff0c;以前思考的时候还是比较着急&#xff0c;现在思考的更多了&#xff0c;现实世界的拼接更加需要我们沉下心来做&#xff0c;尤其是对于更多画面&#xff0c;画面更加清晰怎么做 本篇章不在于其他功能&#xff0c;在…

SpringBoot的图片上传

简介 该文档旨在介绍一个基于Spring Boot框架的简单文件上传功能的实现方式。本文档将详细介绍相关代码的功能和配置以及如何使用它们。 样例 技术栈 Spring Boot&#xff1a;一个用于快速开发基于Spring的应用程序的框架。Thymeleaf&#xff1a;一个用于在Web应用程序中创建…

孔板流量计和孔板流量计真的不一样

孔板流量计和孔板流量计真的不一样&#xff0c;无论您是追求品质&#xff0c;还是注重实用功能&#xff0c;我们的产品都能让您心动不已。让您轻松享受到现代科技所带来的便利&#xff0c;尽情展现自己不一样的魅力。 用途【1-5-9】 孔板流量计为煤矿瓦斯抽放而设的计算瓦斯抽…

vue3.0(五) reactive全家桶

文章目录 1 reactive1.1 reactive的应用1.2 reactive的特点1.3 reactive的注意1.4 reactive的局限性 2 toRefs3 isReactive4 shallowReactive5 readonly5.1 readonly 详细信息5.2 readonly函数创建一个只读的响应式对象5.3 如何修改嵌套在只读响应式对象中的对象? 6 isReadonl…