Qt_QMediaPlayer类与QMediaPlaylist类

Qt QMediaPlayer 类与 QMediaPlaylist 类

Qt Multimedia 模块音频播放核心:媒体播放器 + 播放列表实战手册


目录

文章目录

  • [Qt QMediaPlayer 类与 QMediaPlaylist 类](#Qt QMediaPlayer 类与 QMediaPlaylist 类)
    • 目录
    • [1. Qt 音频基础知识](#1. Qt 音频基础知识)
      • [1.1 引入多媒体模块](#1.1 引入多媒体模块)
      • [1.2 核心类介绍](#1.2 核心类介绍)
      • [1.3 两者关系](#1.3 两者关系)
    • [2. QMediaPlayer 类常用 API](#2. QMediaPlayer 类常用 API)
      • [2.1 基本操作(播放 / 暂停 / 停止)](#2.1 基本操作(播放 / 暂停 / 停止))
      • [2.2 音量控制](#2.2 音量控制)
      • [2.3 播放进度控制](#2.3 播放进度控制)
      • [2.4 状态与错误](#2.4 状态与错误)
      • [2.5 常用信号](#2.5 常用信号)
    • [3. QMediaPlaylist 类常用 API](#3. QMediaPlaylist 类常用 API)
      • [3.1 创建与绑定播放器](#3.1 创建与绑定播放器)
      • [3.2 添加 / 移除媒体条目](#3.2 添加 / 移除媒体条目)
      • [3.3 播放控制](#3.3 播放控制)
      • [3.4 播放模式(重中之重)](#3.4 播放模式(重中之重))
      • [3.5 常用信号](#3.5 常用信号)
    • [4. 完整实战:简易音乐播放器](#4. 完整实战:简易音乐播放器)
      • [4.1 项目文件(.pro)](#4.1 项目文件(.pro))
      • [4.2 音乐播放器核心逻辑](#4.2 音乐播放器核心逻辑)
      • 效果
      • [4.3 界面版补充要点](#4.3 界面版补充要点)
    • [6. 常见坑与 FAQ](#6. 常见坑与 FAQ)
      • [6.1 没有声音 / 提示没有音频输出(Qt 6 专属)](#6.1 没有声音 / 提示没有音频输出(Qt 6 专属))
      • [6.2 播放不了 MP3 等格式](#6.2 播放不了 MP3 等格式)
      • [6.3 进度条不居中 / 位置异常](#6.3 进度条不居中 / 位置异常)
      • [6.4 `previous()` 行为不符合预期](#6.4 previous() 行为不符合预期)
      • [6.5 播放列表如何自动连续播放](#6.5 播放列表如何自动连续播放)
      • [6.6 网络收音机 / 流媒体播放](#6.6 网络收音机 / 流媒体播放)
    • 快速参考表

1. Qt 音频基础知识

1.1 引入多媒体模块

使用音频功能前,需要在 .pro 项目文件中添加多媒体模块:

cpp 复制代码
QT += multimedia

Qt 6 中,QMediaPlayer 与 QMediaPlaylist 属于 Qt Multimedia 模块,同样使用 QT += multimedia。

1.2 核心类介绍

  • QMediaPlayer:媒体播放器,主要用于播放歌曲、网络收音机、视频等功能。它封装了底层音视频解码与播放引擎,提供播放/暂停/停止/定位等操作接口。
  • QMediaPlaylist :专用于播放媒体内容的列表。可以维护一组媒体条目,支持顺序播放、随机播放、循环播放,并能与 QMediaPlayer 绑定实现"播放器 + 歌单"的完整播放体验。

1.3 两者关系

复制代码
QMediaPlaylist(歌单)  ──绑定──>  QMediaPlayer(播放器)  ──输出──>  扬声器/屏幕
      │
      └── 保存多个 QMediaContent / QUrl

QMediaPlaylist 负责"播什么、按什么顺序播",QMediaPlayer 负责"怎么播出来"。二者通过 player->setPlaylist(playlist) 联动。


2. QMediaPlayer 类常用 API

2.1 基本操作(播放 / 暂停 / 停止)

cpp 复制代码
QMediaPlayer *player = new QMediaPlayer(this);

player->setMedia(QUrl::fromLocalFile("D:/music/1.mp3")); // 设置媒体
player->play();     // 播放
player->pause();    // 暂停
player->stop();     // 停止(回到开头)
接口 说明
setMedia(const QMediaContent &) 设置要播放的媒体内容
play() 开始/恢复播放
pause() 暂停播放
stop() 停止播放并复位到开头

2.2 音量控制

cpp 复制代码
player->setVolume(50);  // 设置音量 0 ~ 100
int v = player->volume(); // 获取当前音量

player->setMuted(true);   // 静音
bool m = player->isMuted();
接口 说明
setVolume(int) 设置音量(0~100,Qt 6 为线性 0.0~1.0 见差异)
volume() 获取当前音量
setMuted(bool) 静音开关
isMuted() 是否静音

2.3 播放进度控制

cpp 复制代码
player->setPosition(30000);     // 跳到 30 秒处(毫秒)
qint64 pos = player->position(); // 当前播放位置(毫秒)
qint64 dur = player->duration(); // 媒体总时长(毫秒)
bool avail = player->isSeekable(); // 是否可定位
接口 说明
setPosition(qint64) 设置播放位置(毫秒)
position() 当前播放位置
duration() 媒体总时长(-1 表示未知)
isSeekable() 是否支持定位

2.4 状态与错误

cpp 复制代码
QMediaPlayer::State state = player->state();           // 播放状态
QMediaPlayer::MediaStatus status = player->mediaStatus(); // 媒体加载状态
QMediaPlayer::Error err = player->error();             // 错误码
QString errStr = player->errorString();                // 错误描述

State 枚举(播放状态):

值 说明
StoppedState 停止
PlayingState 播放中
PausedState 已暂停

MediaStatus 枚举(媒体状态):

值 说明
NoMedia 未设置媒体
LoadingMedia 正在加载
LoadedMedia 已加载
BufferingMedia 缓冲中
BufferedMedia 缓冲完成
EndOfMedia 播放到结尾
InvalidMedia 媒体无效(无法播放)

2.5 常用信号

cpp 复制代码
connect(player, &QMediaPlayer::positionChanged,  this, [=](qint64 pos){
    ui->slider->setValue(pos);          // 更新进度条
});
connect(player, &QMediaPlayer::durationChanged, this, [=](qint64 dur){
    ui->slider->setMaximum(dur);        // 设置进度条最大值
});
connect(player, &QMediaPlayer::stateChanged,  this, [=](QMediaPlayer::State s){
    if (s == QMediaPlayer::PlayingState)
        ui->btnPlay->setText("暂停");
    else
        ui->btnPlay->setText("播放");
});
connect(player, &QMediaPlayer::mediaStatusChanged, this, [=](QMediaPlayer::MediaStatus s){
    if (s == QMediaPlayer::EndOfMedia)
        ; // 单曲播放结束处理
});
信号 触发时机
positionChanged(qint64) 播放位置变化
durationChanged(qint64) 时长已知/变化
stateChanged(State) 播放状态变化
volumeChanged(int) 音量变化
mutedChanged(bool) 静音状态变化
mediaStatusChanged(MediaStatus) 媒体加载状态变化
error(QMediaPlayer::Error) 发生错误

3. QMediaPlaylist 类常用 API

3.1 创建与绑定播放器

cpp 复制代码
QMediaPlaylist *playlist = new QMediaPlaylist(this);

QMediaPlayer *player = new QMediaPlayer(this);
player->setPlaylist(playlist); // 将歌单绑定到播放器
player->setVolume(60);
player->play();

绑定后,播放器播放的将是歌单中的内容,无需再单独 setMedia()。

3.2 添加 / 移除媒体条目

cpp 复制代码
playlist->addMedia(QUrl::fromLocalFile("D:/music/1.mp3")); // 添加单个
playlist->addMedia(QUrl::fromLocalFile("D:/music/2.mp3"));

// 批量添加
QList<QMediaContent> list;
for (QString &f : files)
    list << QMediaContent(QUrl::fromLocalFile(f));
playlist->addMedia(list);

// 在指定位置插入 / 移除
playlist->insertMedia(0, QMediaContent(QUrl::fromLocalFile("x.mp3")));
playlist->removeMedia(0);        // 移除下标 0 的条目
playlist->clear();               // 清空歌单
接口 说明
addMedia(const QMediaContent &) 末尾添加单条
addMedia(const QList<QMediaContent> &) 批量添加
insertMedia(int, const QMediaContent &) 指定位置插入
removeMedia(int) 移除指定下标条目
clear() 清空全部
mediaCount() 条目数量

3.3 播放控制

cpp 复制代码
playlist->next();         // 下一首
playlist->previous();     // 上一首
playlist->setCurrentIndex(2); // 跳到第 3 首
int idx = playlist->currentIndex(); // 当前曲目下标
QMediaContent cur = playlist->currentMedia(); // 当前媒体
接口 说明
next() 跳到下一首(受播放模式影响)
previous() 跳到上一首
setCurrentIndex(int) 跳到指定下标
currentIndex() 当前下标
currentMedia() 当前媒体内容

3.4 播放模式(重中之重)

cpp 复制代码
playlist->setPlaybackMode(QMediaPlaylist::Loop);      // 列表循环
playlist->setPlaybackMode(QMediaPlaylist::Random);    // 随机播放
playlist->setPlaybackMode(QMediaPlaylist::Sequential); // 顺序播放(默认)
playlist->setPlaybackMode(QMediaPlaylist::CurrentItemInLoop); // 单曲循环

PlaybackMode 枚举:

值 说明
CurrentItemOnce 当前曲目播放一次即停
CurrentItemInLoop 单曲循环
Sequential 顺序播放(放完即停)
Loop 列表循环
Random 随机播放

3.5 常用信号

cpp 复制代码
connect(playlist, &QMediaPlaylist::currentIndexChanged, this, [=](int i){
    ui->labelSongName->setText(...); // 切换曲目时更新界面
});
connect(playlist, &QMediaPlaylist::mediaCountChanged, this, [=](int c){
    ; // 歌单数量变化
});
信号 触发时机
currentIndexChanged(int) 当前曲目下标变化
currentMediaChanged(const QMediaContent &) 当前媒体变化
mediaCountChanged(int) 歌单数量变化
playbackModeChanged(PlaybackMode) 播放模式变化

4. 完整实战:简易音乐播放器

一个可直接运行的控制台/界面最小示例,演示"歌单 + 播放器"联动。

4.1 项目文件(.pro)

cpp 复制代码
QT       += core gui multimedia

4.2 音乐播放器核心逻辑

cpp 复制代码
// ================================================================
// QAudioFrePro.cpp
// Mp3 音频播放器主窗口的实现文件
// 负责:播放器/播放列表的创建与信号槽连接、歌曲加载与播放控制、
//       音量控制、进度显示与跳转、双击列表选歌等交互逻辑
// ================================================================

#include "QAudioFrePro.h"

// ---- Qt 核心/工具类 ----
// QDebug:调试输出(qDebug()),排查问题时使用
#include <QDebug>
// QDir:目录操作,这里用于获取用户主目录作为文件对话框的默认路径
#include <QDir>
// QFileInfo:文件信息,这里用于从完整路径中取出文件名(去掉目录部分)
#include <QFileInfo>
// QIcon:图标类,用于切换"有声音 / 静音"按钮的图标
#include <QIcon>
// QUrl:统一资源定位符,本地文件路径需要转换成 QUrl 才能交给播放器
#include <QUrl>

// ================================================================
// 构造函数:完成界面装载、播放器与播放列表初始化、信号槽连接
// ================================================================
QAudioFrePro::QAudioFrePro(QWidget *parent) : QMainWindow(parent) {
  // 装载 .ui 文件生成的界面,把界面上的控件挂到 this 上
  // 同时会自动查找本类中符合 on_<控件名>_<信号名> 规则的槽函数并完成连接
  // (例如 on_pushButton_open_clicked、on_horizontalSlider_volume_valueChanged
  // 等)
  ui.setupUi(this);

  // 创建播放器:this 作为父对象,内存由 this 自动管理
  player = new QMediaPlayer(this);
  // 创建播放列表:this 作为父对象,内存由 this 自动管理
  playlist = new QMediaPlaylist(this);
  // 设置播放列表的循环方式:
  // Loop          = 整个列表循环播放(播完最后一首回到第一首)
  // Sequential    = 按顺序播放,播完停止
  // CurrentItemInLoop = 单曲循环
  // Random        = 随机播放
  playlist->setPlaybackMode(QMediaPlaylist::Loop);
  // 把播放列表设置给播放器,之后播放器就会按照列表中的媒体依次播放
  player->setPlaylist(playlist);

  // --- 下面把播放器的各种状态信号连接到界面的槽函数 ---
  // stateChanged(State):播放状态改变(停止/播放/暂停)时触发,
  //                      槽函数 onstatechg
  //                      用来切换"播放/暂停/停止"按钮的可用状态
  connect(player, SIGNAL(stateChanged(QMediaPlayer::State)), this,
          SLOT(onstatechg(QMediaPlayer::State)));
  // positionChanged(qint64):播放位置变化时持续触发(毫秒),
  //                          槽函数 onptchg
  //                          用来刷新进度条与"当前进度/总时长"文本
  connect(player, SIGNAL(positionChanged(qint64)), this, SLOT(onptchg(qint64)));
  // durationChanged(qint64):当前媒体的总时长确定后触发(毫秒),
  //                          槽函数 onDrtchg 用来设置进度条的最大值并保存总时长
  connect(player, SIGNAL(durationChanged(qint64)), this,
          SLOT(onDrtchg(qint64)));
  // currentIndexChanged(int):播放列表当前曲目索引改变时触发,
  //                           槽函数 onplaylistchg 用来同步列表高亮与歌曲名标签
  connect(playlist, SIGNAL(currentIndexChanged(int)), this,
          SLOT(onplaylistchg(int)));

  // 初始化音量:音量滑块在 .ui 中默认值为 50,
  // 而播放器默认音量是 100,因此启动时把播放器音量与界面滑块的值保持一致
  player->setVolume(ui.horizontalSlider_volume->value());
}

// ================================================================
// 析构函数
// player、playlist 都以 this 为父对象,Qt 会随窗口一起自动销毁,
// 因此这里无需手动 delete
// ================================================================
QAudioFrePro::~QAudioFrePro() {}

// ================================================================
// 【打开】按钮:弹出文件对话框,把选中的音频文件加入播放列表并播放
// 信号:pushButton_open 的 clicked()
// ================================================================
void QAudioFrePro::on_pushButton_open_clicked() {
  // getOpenFileNames 可一次选择多个文件,返回选中的完整路径列表
  // 参数依次为:父窗口、对话框标题、默认打开目录(用户主目录)、文件类型过滤器
  QStringList fileNames = QFileDialog::getOpenFileNames(
      this, tr("选择音频文件"), QDir::homePath(),
      tr("音频文件 (*.mp3 *.wav *.flac *.ogg *.aac *.wma);;所有文件 (*.*)"));

  // 用户点了"取消"或没有选择任何文件时直接返回,不做任何处理
  if (fileNames.isEmpty())
    return;

  // 遍历用户选中的每个文件:
  for (const QString &fileName : fileNames) {
    // 1) 把本地路径转换成 QUrl
    // 后加入播放列表(注意是增量添加,不会清空已有歌曲)
    playlist->addMedia(QUrl::fromLocalFile(fileName));
    // 2) 取出文件名(不含目录,例如 "C:\music\a.mp3" ->
    // "a.mp3")显示到列表控件,
    //    行号顺序与播放列表中的索引一一对应,供双击/切歌时互相定位
    ui.listWidget_MusicList->addItem(QFileInfo(fileName).fileName());
  }

  // 若之前还没有任何歌曲(currentIndex 为 -1),把播放列表定位到第一首
  if (playlist->mediaCount() > 0 && playlist->currentIndex() < 0)
    playlist->setCurrentIndex(0);
  // 开始播放(列表切换曲目会触发 onplaylistchg 同步界面高亮)
  player->play();
}

// ================================================================
// 【播放】按钮:播放当前选中的歌曲
// 信号:pushButton_play 的 clicked()
// 说明:首次播放前必须先通过"打开"按钮添加歌曲
// ================================================================
void QAudioFrePro::on_pushButton_play_clicked() {
  // 播放列表为空时什么都不做,避免无效操作
  if (playlist->mediaCount() <= 0)
    return; // 还没有歌曲,请先点击"打开"

  // 如果还没有选中任何歌曲(例如打开文件后处于停止状态),定位到第一首
  if (playlist->currentIndex() < 0)
    playlist->setCurrentIndex(0);
  // 开始/继续播放(若处于暂停状态,play() 会从暂停位置继续)
  player->play();
}

// ================================================================
// 【暂停】按钮:暂停当前播放
// 信号:pushButton_pause 的 clicked()
// 说明:暂停后再次点击"播放"会从暂停位置继续,而不是从头播放
// ================================================================
void QAudioFrePro::on_pushButton_pause_clicked() { player->pause(); }

// ================================================================
// 【停止】按钮:停止当前播放
// 信号:pushButton_stop 的 clicked()
// 说明:停止后再点"播放",歌曲会从头开始
// ================================================================
void QAudioFrePro::on_pushButton_stop_clicked() { player->stop(); }

// ================================================================
// 【上一曲】按钮:切到播放列表的上一首并播放
// 信号:pushButton_previous 的 clicked()
// ================================================================
void QAudioFrePro::on_pushButton_previous_clicked() {
  // 列表为空时不响应
  if (playlist->mediaCount() <= 0)
    return;
  // previous():跳到上一首;若当前是第一首且模式为 Loop,会循环到最后一首
  playlist->previous();
  // 切歌后立即开始播放
  player->play();
}

// ================================================================
// 【下一曲】按钮:切到播放列表的下一首并播放
// 信号:pushButton_next 的 clicked()
// ================================================================
void QAudioFrePro::on_pushButton_next_clicked() {
  // 列表为空时不响应
  if (playlist->mediaCount() <= 0)
    return;
  // next():跳到下一首;若当前是最后一首且模式为 Loop,会循环回到第一首
  playlist->next();
  // 切歌后立即开始播放
  player->play();
}

// ================================================================
// 【音量】按钮:在"静音"和"取消静音"之间切换(即打开/关闭声音)
// 信号:pushButton_volume 的 clicked()
// 说明:静音时图标切换为 mute.bmp,恢复声音时图标切回 volumn.bmp
// ================================================================
void QAudioFrePro::on_pushButton_volume_clicked() {
  if (player->isMuted()) {
    // 当前是静音状态 -> 取消静音
    player->setMuted(false);
    ui.pushButton_volume->setIcon(QIcon(":/QAudioFrePro/images/volumn.bmp"));
  } else {
    // 当前有声音 -> 开启静音
    player->setMuted(true);
    ui.pushButton_volume->setIcon(QIcon(":/QAudioFrePro/images/mute.bmp"));
  }
}

// ================================================================
// 【音量滑块】槽函数:用户拖拽滑块时实时调整音量大小
// 信号:horizontalSlider_volume 的 valueChanged(int),value 取值 0~100
// ================================================================
void QAudioFrePro::on_horizontalSlider_volume_valueChanged(int value) {
  // 把滑块的数值(0~100)直接设置为播放器的音量
  player->setVolume(value);
  // 若当前处于静音状态,只要拖动滑块就自动解除静音并恢复图标,
  // 避免"拖了滑块却没声音"让用户误以为坏了
  if (player->isMuted()) {
    player->setMuted(false);
    ui.pushButton_volume->setIcon(QIcon(":/QAudioFrePro/images/volumn.bmp"));
  }
}

// ================================================================
// 【播放进度滑块】槽函数:拖拽结束后把歌曲跳转到滑块所在位置
// 信号:horizontalSlider_spead 的 sliderReleased()(鼠标松开时触发)
// 说明:不使用 valueChanged 是因为播放中 onptchg 会不断刷新滑块位置,
//       若实时跳转会相互干扰、造成拖拽抖动;松手时一次性跳转体验更好,
//       且与 onptchg 中 isSliderDown() 的防冲突逻辑配合良好。
// ================================================================
void QAudioFrePro::on_horizontalSlider_spead_sliderReleased() {
  // 进度条最大值为歌曲总时长(onDrtchg 中设置),value 单位与播放位置一致(毫秒),
  // 直接把当前滑块值作为目标播放位置即可
  player->setPosition(ui.horizontalSlider_spead->value());
}

// ================================================================
// 【歌曲列表】双击槽函数:双击列表中的某首歌,立即播放它
// 信号:listWidget_MusicList 的 itemDoubleClicked(QListWidgetItem*)
// ================================================================
void QAudioFrePro::on_listWidget_MusicList_itemDoubleClicked(
    QListWidgetItem *item) {
  // 防御性检查:双击的对象不应为空
  if (!item)
    return;

  // row(item) 返回该项所在的行号。因为"打开"时是把文件逐个同步加入
  // 播放列表与列表控件的,行号与播放列表索引一一对应
  int row = ui.listWidget_MusicList->row(item);
  // 越界检查,防止索引超出播放列表范围
  if (row < 0 || row >= playlist->mediaCount())
    return;

  // 把播放列表的当前曲目切换到该行,会触发 currentIndexChanged 信号,
  // 由 onplaylistchg 同步列表高亮与左侧歌曲名标签
  playlist->setCurrentIndex(row);
  // 开始播放被双击的歌曲
  player->play();
}

// ================================================================
// 播放状态变化槽函数:根据播放状态切换下方控制按钮的可用性
// 信号:QMediaPlayer::stateChanged(QMediaPlayer::State)
// State 取值:StoppedState(停止) / PlayingState(播放中) / PausedState(已暂停)
// ================================================================
void QAudioFrePro::onstatechg(QMediaPlayer::State state) {
  // 播放中 -> "播放"按钮禁用(当前正在播放无需再点),否则启用
  ui.pushButton_play->setEnabled(!(state == QMediaPlayer::PlayingState));
  // 播放中 -> "暂停"按钮启用,可点击暂停;非播放状态禁用
  ui.pushButton_pause->setEnabled(state == QMediaPlayer::PlayingState);
  // 播放中 -> "停止"按钮启用,可点击停止;非播放状态禁用
  ui.pushButton_stop->setEnabled(state == QMediaPlayer::PlayingState);
}

// ================================================================
// 播放列表当前曲目变化槽函数:同步界面上的选中高亮与歌曲名标签
// 信号:QMediaPlaylist::currentIndexChanged(int pos),pos 为新的曲目索引
// ================================================================
void QAudioFrePro::onplaylistchg(int pos) {
  // 让列表控件高亮播放中的那一行(对应上一曲/下一曲/双击/自动切歌等场景)
  ui.listWidget_MusicList->setCurrentRow(pos);
  // 取出当前选中的列表项
  QListWidgetItem *item = ui.listWidget_MusicList->currentItem();
  // 若存在该项,则把歌曲名显示到界面的"歌曲名称"标签上
  if (item)
    ui.label_mucName->setText(item->text());
}

// ================================================================
// 歌曲总时长变化槽函数:设置进度条最大值并保存总时长文本
// 信号:QMediaPlayer::durationChanged(qint64 drt),drt 为毫秒
// ================================================================
void QAudioFrePro::onDrtchg(qint64 drt) {
  // 进度条最大值设为总时长,这样进度条 0 ~ 最大值 恰好对应 0 ~ 总时长
  ui.horizontalSlider_spead->setMaximum(drt);
  // 毫秒 -> 秒
  int sec = drt / 1000;
  // 秒 -> 分钟(整除)
  int min = sec / 60;
  // 去掉整分钟后的剩余秒数
  sec = sec % 60;

  // 格式化为 "分:秒"(不足两位补 0,例如 03:05),保存为歌曲总时长
  drtTime = QString::asprintf("%02d:%02d", min, sec);
  // 显示格式:"当前进度 / 总时长",当前进度部分由 onptchg 维护
  ui.label_time->setText(pstTime + " / " + drtTime);
}

// ================================================================
// 播放位置变化槽函数:刷新进度条位置与"当前进度/总时长"文本
// 信号:QMediaPlayer::positionChanged(qint64 pos),pos 为毫秒
// ================================================================
void QAudioFrePro::onptchg(qint64 pos) {
  // 若用户正在按住进度条拖拽(isSliderDown 为 true),
  // 则跳过本次刷新,避免程序与用户"抢"滑块位置,保证拖拽顺畅;
  // 等用户松手后由 on_horizontalSlider_spead_sliderReleased 完成跳转
  if (ui.horizontalSlider_spead->isSliderDown()) {
    return;
  }
  // 把进度条滑块移动到当前播放位置(setSliderPosition 不会触发 valueChanged,
  // 因此不会反向干扰播放)
  ui.horizontalSlider_spead->setSliderPosition(pos);

  // 与 onDrtchg 相同的换算:毫秒 -> 分:秒 文本
  int sec = pos / 1000;                               // 秒
  int min = sec / 60;                                 // 分
  sec = sec % 60;                                     // 余数为秒
  pstTime = QString::asprintf("%02d:%02d", min, sec); // 保存当前播放进度
  // 实时刷新时间标签:当前进度 / 总时长
  ui.label_time->setText(pstTime + " / " + drtTime);
}

效果

4.3 界面版补充要点

若使用 Qt Widgets 界面,建议:

  • 用 QSlider 作为进度条,绑定 positionChanged 更新滑块、sliderMoved 触发 setPosition。
  • 用 QLabel 显示当前曲目名,绑定 currentIndexChanged。
  • 用 QPushButton 控制播放/暂停/上一首/下一首。
  • 用 QListWidget 显示歌单,双击条目调用 setCurrentIndex(row)。

6. 常见坑与 FAQ

6.1 没有声音 / 提示没有音频输出(Qt 6 专属)

Qt 6 中必须手动创建 QAudioOutput:

cpp 复制代码
QAudioOutput *audioOutput = new QAudioOutput(this);
player->setAudioOutput(audioOutput);
audioOutput->setVolume(0.5f);

6.2 播放不了 MP3 等格式

确认两方面:

  1. 项目文件已加 QT += multimedia。
  2. 系统/后端解码器支持该格式。Qt 依赖系统多媒体框架(Windows 用 WMF/DirectShow,Linux 用 GStreamer),确保系统能播放该格式。

6.3 进度条不居中 / 位置异常

  • duration() 在媒体加载完成后才有有效值(LoadedMedia 之后)。请在 durationChanged 或 mediaStatusChanged == LoadedMedia 后再设置进度条最大值。
  • 定位前先判断 isSeekable()。

6.4 previous() 行为不符合预期

previous() 在播放超过约 1.5 秒后,大多实现是"回到当前曲目开头"而非"上一首"。要实现真正"上一首",可自行记录历史或连续调用两次(视后端而定)。

6.5 播放列表如何自动连续播放

绑定播放器后,一首播完会自动根据 PlaybackMode 播放下一首,无需手动 connect。若需在最后一首播完停止,用 Sequential 模式即可。

6.6 网络收音机 / 流媒体播放

cpp 复制代码
player->setMedia(QMediaContent(QUrl("http://example.com/stream"))); // Qt 5
player->setSource(QUrl("http://example.com/stream"));                // Qt 6
player->play();

缓冲状态可通过 mediaStatusChanged 的 BufferingMedia / BufferedMedia 判断。


快速参考表

需求 关键调用
播放文件 player->setMedia(...) / setSource(...) + play()
暂停/继续 player->pause() / player->play()
停止 player->stop()
调音量 player->setVolume(...)
静音 player->setMuted(true)
定位 player->setPosition(ms)
获取进度 player->position()
获取时长 player->duration()
绑定歌单 player->setPlaylist(playlist)
添加歌曲 playlist->addMedia(...)
下一首 playlist->next()
上一首 playlist->previous()
跳到第 N 首 playlist->setCurrentIndex(N)
列表循环 playlist->setPlaybackMode(QMediaPlaylist::Loop)
随机播放 playlist->setPlaybackMode(QMediaPlaylist::Random)
单曲循环 playlist->setPlaybackMode(QMediaPlaylist::CurrentItemInLoop)

完结

相关推荐
小羊没烦恼!3 天前
初探性能优化——2个月到4小时的性能提升
java·开发语言·windows·算法·c#
伞伞悦读3 天前
【第38期】Python 模块与包详解:import、from、模块搜索路径、包结构和 __init__
开发语言·python
C语言小火车3 天前
C/C++ 为什么需要编译器?
开发语言·c++
霍霍的袁3 天前
【C++】map 和 set 的使用 | 从用法到底层
开发语言·c++·学习·visual studio
孙启超3 天前
【AI开发之Rust】第 11 课:智能指针与内部可变性
开发语言·后端·rust
此生决int3 天前
深入理解C++系列(20)——C++11(下)
开发语言·c++
慧都小项3 天前
当边缘AI上产线:QtitanDocking 如何让工业 HMI 实现多视图协同
人工智能·qt·ui·边缘计算·qt6.3
CoderYanger3 天前
A.每日一题:835. 图像重叠
java·开发语言·程序人生·leetcode·面试·职场和发展·学习方法
伞伞悦读3 天前
【第37期】Python JSON 与配置详解:序列化、反序列化、嵌套结构和配置文件
开发语言·python·json
CCCCCCCCharlie3 天前
Linux进程控制四大核心操作
linux·开发语言