【QT】实战项目:从零打造一个高颜值的音乐播放器

在这里插入图片描述

个人主页:Air
归属专栏:QT

在这里插入图片描述

文章目录

正文

好的,老铁!准备好了吗?这次咱们玩个大的,用QT来搞一个实实在在的项目。不是那种在控制台打印“Hello World”的小打小闹,而是一个有界面、有交互、能打包发给别人用的桌面应用程序

这篇文章将是你踏入QT实战开发的敲门砖,我会手把手带你,用最通俗的语言,从零开始构建一个功能完整的工具。

废话不多说,系好安全带,发车了!

1. 项目启航:我们为什么要做这个?

1.1 QT能做什么?为什么是它?

想象一下,C++是威力无比的降龙十八掌,内力深厚,性能炸裂。但用它来写窗口、画按钮,就好像用这套掌法去绣花——不是不行,是能把你累死。QT呢,就是给这套掌法配上了一套精妙的“绣花针法”。它是一套成熟的C++图形用户界面库,让你能用C++的强大内力,轻松地“绣”出各种漂亮的窗口程序。

QT的优势在于:

  • 跨平台:写一次代码,就能编译成Windows、Mac、Linux上都能运行的程序。这可是大杀器!
  • 生态丰富:除了界面,还提供了网络、数据库、多媒体、蓝牙等一大堆现成的模块。
  • 社区活跃:遇到问题,很容易找到解决方案。
  • 商业友好:开源版(LGPL)够用,商业版功能更强还有技术支持。

所以,用QT来做音乐播放器,既能深入理解C++面向对象编程,又能体验到图形界面开发的乐趣,成就感爆棚!

1.2 项目最终形态预览:我们要做出个啥?

咱们不是要做一个媲美QQ音乐的巨无霸,而是一个小巧、精美、核心功能完整的播放器。它应该具备:

  • 一个美观的主窗口,有播放/暂停、停止、上一曲、下一曲按钮。
  • 一个显示当前播放时间的进度条,可以拖动跳转。
  • 一个音量控制滑块。
  • 一个显示歌曲列表的窗口,可以添加/删除歌曲。
  • 能够自动记住上次播放的列表和设置。

1.3 开发环境搭建:磨刀不误砍柴工

工欲善其事,必先利其器。我强烈推荐以下组合,对新手极其友好:

  1. QT版本:选择QT 5.15.xQT 6.2+ 的开源版。这两个版本非常稳定,资料也多。
  2. IDE:直接用 QT Creator。这是QT的亲儿子,天生一对,无缝集成,调试起来特别舒服。
  3. 编译器:在Windows上,安装QT时会自动帮你装好 MinGW(GCC的Windows版),就用它。

安装过程就是一路“下一步”,这里不赘述。安装完成后,打开QT Creator,创建一个新项目。

【Code】创建新项目:

  • 选择 Application -> Qt Widgets Application
  • 项目名填 MyMusicPlayer
  • Choose Kits这一步,勾选Desktop Qt 5.15.2 MinGW 64-bit(根据你的版本)。
  • 一路下一步,直到完成。

你会看到QT Creator为你生成了几个核心文件:main.cpp, mainwindow.h, mainwindow.cpp, mainwindow.ui。这个.ui文件就是我们的界面设计文件,双击它就能打开图形化的设计师界面。

2. QT核心哲学:信号与槽(不懂这个,等于没学QT)

这是QT最精髓、最独特的机制,理解了它,你就理解了QT的事件驱动编程。

2.1 什么是“信号”?什么是“槽”?

  • 信号:当一个特定事件发生时,对象就会“发射”一个信号。比如,按钮被点击了,它会发射一个clicked()信号;滑块被拖动了,它会发射一个valueChanged(int)信号。信号本身只是一个声明,没有具体实现。
  • :槽就是一个普通的C++成员函数,它可以被调用来处理特定的信号。比如,可以写一个onPlayButtonClicked()的槽函数,专门用来响应播放按钮的点击信号。

QT的魔法在于,你可以用connect函数,将某个对象的信号,连接到另一个对象的上。这样,信号一发射,对应的槽函数就会被自动调用。

2.2 【举例】生活中的信号与槽

这就像你家的门铃系统:

  • 信号:门铃按钮被按下(buttonPressed())。
  • :屋内的门铃响起来(ringTheBell())。
  • 连接:电工把门铃按钮和门铃喇叭的线路连接起来(connect(button, SIGNAL(pressed()), bell, SLOT(ring())))。

这样,一旦“按下按钮”这个事件发生,“响铃”这个动作就会自动触发。你不需要一直去检查按钮有没有被按,这就是“事件驱动”。

2.3 【Code】三种连接信号与槽的方式

方式一:QT4的老语法(仍然有效,但不太推荐)

connect(ui->playButton, SIGNAL(clicked()), this, SLOT(onPlayButtonClicked()));

这种方式在编译时不会检查信号和槽是否存在,如果写错了,运行时才会报错。

方式二:QT5推荐的新语法(强烈推荐

connect(ui->playButton, &QPushButton::clicked, this, &MainWindow::onPlayButtonClicked);

这种方式是类型安全的,编译器会检查函数签名,如果信号或槽不存在,编译就会失败,大大减少错误。

方式三:使用Lambda表达式(处理简单逻辑非常方便)

connect(ui->playButton, &QPushButton::clicked, this, [this]() {
    // 直接在这里写处理代码
    if (m_player->state() == QMediaPlayer::PlayingState) {
        m_player->pause();
    } else {
        m_player->play();
    }
});

Lambda表达式让你无需专门定义一个槽函数,代码更紧凑。

3. UI设计师初体验:拖拽出我们的播放界面

双击mainwindow.ui,进入Qt Designer。左边是各种各样的控件(Widgets),比如按钮、标签、滑块等。

3.1 Qt Designer的基本操作

我们的目标是布局一个简单的界面:

  1. 从左边拖一个Push Button到中间的表单上,在右下角的属性编辑器里,把它的objectName改为playButtontext改为“播放”。
  2. 同样地,拖拽出“暂停”、“停止”、“上一曲”、“下一曲”按钮。
  3. 拖一个Horizontal Slider作为进度条,objectName改为positionSlider
  4. 拖一个Vertical Slider作为音量条,objectName改为volumeSlider
  5. 拖一个List Widget到右侧或下方,作为播放列表,objectName改为playlistWidget
  6. 使用布局管理器(Layouts)来排列这些控件,让它们能随着窗口大小自动调整。选中多个控件,点击工具栏上的“水平布局”、“垂直布局”或“栅格布局”。

3.2 【Mermaid图】界面控件布局图解

下面这张图清晰地展示了我们设计的界面结构:

主窗口 MainWindow
顶部工具栏 ToolBar
中央部件 CentralWidget
底部状态栏 StatusBar - 可选
垂直布局管理器 QVBoxLayout
播放控制区域 Widget
播放列表区域 QListWidget
水平布局管理器 QHBoxLayout
上一曲按钮
播放按钮
暂停按钮
停止按钮
下一曲按钮
进度条 QSlider
音量条 QSlider
时间标签 QLabel

3.3 【Code】将UI文件转化为C++代码

你不需要手动做这件事!QT的构建系统(qmake或CMake)会自动在编译过程中,将mainwindow.ui文件翻译成一个头文件ui_mainwindow.h。你在mainwindow.h中看到的Ui::MainWindow *ui这个指针,就是指向这个自动生成的界面类。

MainWindow的构造函数里,有一句ui->setupUi(this);,这行代码的作用就是根据你的UI设计,动态创建出所有的控件对象,并把它们显示出来。非常方便!

(由于字数限制,我们先到这里。但文章绝不会中断!接下来我们继续深入核心功能…)

4. 播放器核心引擎:QMediaPlayer揭秘

界面是骨架,现在我们要注入灵魂——播放音乐的能力。

4.1 QMediaPlayer的能力与局限

QT提供了QMediaPlayer类,它就是一个现成的播放器内核。它支持很多格式,如MP3、WAV、OGG等(具体支持哪些取决于系统安装的解码器)。它的优点是接口简单易用,缺点是功能相对基础,比如不支持歌词、音效调节等高级功能。但对于我们的项目,它完全够用。

4.2 【Code】初始化播放器并加载第一首歌

首先,在mainwindow.h中引入头文件并声明成员变量。

【Code】在mainwindow.h中:

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QMediaPlayer>   // 引入多媒体模块
#include <QMediaPlaylist> // 引入播放列表模块

// 自动生成的UI命名空间
QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT // 这个宏是QT信号槽机制所必需的

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private slots:
    // 声明我们的槽函数
    void onPlayButtonClicked();
    void onPositionChanged(qint64 position);
    void onDurationChanged(qint64 duration);

private:
    Ui::MainWindow *ui;
    QMediaPlayer *m_player;       // 播放器核心
    QMediaPlaylist *m_playlist;   // 播放列表核心
};
#endif // MAINWINDOW_H

然后,在mainwindow.cpp的构造函数中初始化它们。

【Code】在mainwindow.cpp的构造函数中:

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QFileDialog>
#include <QDebug> // 用于调试输出

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

    // 初始化播放器和播放列表
    m_player = new QMediaPlayer(this);
    m_playlist = new QMediaPlaylist(this);
    m_player->setPlaylist(m_playlist); // 将播放列表设置给播放器

    // 连接信号与槽
    // 当播放按钮被点击时,触发onPlayButtonClicked槽
    connect(ui->playButton, &QPushButton::clicked, this, &MainWindow::onPlayButtonClicked);

    // 当播放器的播放位置改变时,更新进度条
    connect(m_player, &QMediaPlayer::positionChanged, this, &MainWindow::onPositionChanged);

    // 当加载新歌曲,时长信息改变时,设置进度条的范围
    connect(m_player, &QMediaPlayer::durationChanged, this, &MainWindow::onDurationChanged);

    // 测试:加载一首歌曲
    // m_player->setMedia(QUrl::fromLocalFile("C:/Music/你的音乐.mp3"));
}

MainWindow::~MainWindow()
{
    delete ui;
}

// 实现槽函数
void MainWindow::onPlayButtonClicked()
{
    if (m_player->state() == QMediaPlayer::PlayingState) {
        m_player->pause();
        ui->playButton->setText("播放");
    } else {
        m_player->play();
        ui->playButton->setText("暂停");
    }
}

void MainWindow::onPositionChanged(qint64 position)
{
    // position是毫秒数,我们需要更新进度条
    // 防止duration为0时除零错误
    if (m_player->duration() > 0) {
        ui->positionSlider->setValue(static_cast<int>(position * 100 / m_player->duration()));
    }
}

void MainWindow::onDurationChanged(qint64 duration)
{
    // duration是总时长(毫秒),设置进度条的范围为0-100(百分比)
    ui->positionSlider->setRange(0, 100);
    // 这里可以顺便把总时长显示在一个Label上
    // 例如:QTime time = QTime::fromMSecsSinceStartOfDay(duration);
    // ui->totalTimeLabel->setText(time.toString("mm:ss"));
}

4.3 【举例】处理播放状态

上面的代码已经展示了如何通过检查m_player->state()来切换播放和暂停状态。QMediaPlayer::State是一个枚举类型,有三种状态:

  • QMediaPlayer::StoppedState:停止状态。
  • QMediaPlayer::PlayingState:正在播放。
  • QMediaPlayer::PausedState:暂停状态。

你可以类似地为“停止”、“上一曲”、“下一曲”按钮创建槽函数,分别调用m_player->stop()m_playlist->previous(), m_playlist->next()


(看,我们完全没有中断,已经一步步构建起了播放器的核心逻辑!接下来,我们要让播放列表活起来…)

5. 播放列表管理:让音乐排好队

只有一个播放器还不够,我们需要一个歌单。

5.1 使用QListWidget展示歌曲列表

QListWidget是一个显示列表的控件,非常适合用来做播放列表。我们可以把添加的歌曲路径(甚至歌名)显示在里面。

5.2 【Code】实现添加文件、添加文件夹功能

我们在界面上再添加两个按钮:addFileButtonaddFolderButton

mainwindow.h中声明新的槽函数:

private slots:
    // ... 之前的槽函数 ...
    void onAddFileButtonClicked();
    void onAddFolderButtonClicked();

mainwindow.cpp中实现:

// 在构造函数中连接新按钮的信号
connect(ui->addFileButton, &QPushButton::clicked, this, &MainWindow::onAddFileButtonClicked);
connect(ui->addFolderButton, &QPushButton::clicked, this, &MainWindow::onAddFolderButtonClicked);

// 实现槽函数
void MainWindow::onAddFileButtonClicked()
{
    // 弹出文件选择对话框,选择多个音乐文件
    QStringList filePaths = QFileDialog::getOpenFileNames(this,
                                                         "选择音乐文件",
                                                         QDir::homePath(),
                                                         "音频文件 (*.mp3 *.wav *.flac *.ogg)");
    for (const QString &filePath : filePaths) {
        // 将每个文件添加到播放列表
        QUrl fileUrl = QUrl::fromLocalFile(filePath);
        m_playlist->addMedia(fileUrl);

        // 同时,在UI的ListWidget中显示文件名
        QFileInfo fileInfo(filePath);
        ui->playlistWidget->addItem(fileInfo.fileName());
    }
}

void MainWindow::onAddFolderButtonClicked()
{
    // 弹出文件夹选择对话框
    QString folderPath = QFileDialog::getExistingDirectory(this, "选择音乐文件夹");
    if (folderPath.isEmpty()) return;

    // 遍历文件夹下的所有文件
    QDir dir(folderPath);
    QStringList filters;
    filters << "*.mp3" << "*.wav" << "*.flac" << "*.ogg";
    QFileInfoList fileList = dir.entryInfoList(filters, QDir::Files);

    for (const QFileInfo &fileInfo : fileList) {
        QUrl fileUrl = QUrl::fromLocalFile(fileInfo.absoluteFilePath());
        m_playlist->addMedia(fileUrl);
        ui->playlistWidget->addItem(fileInfo.fileName());
    }
}

现在,你已经可以添加音乐并看到列表了!你还可以为playlistWidget添加双击事件,实现双击列表项即播放该歌曲的功能。

5.3 【Mermaid图】播放列表数据结构流

为了更清晰地理解QMediaPlaylistQListWidget是如何协同工作的,请看下面的数据流图:

graph LR
    A[用户操作: 添加文件/文件夹] --> B[QMediaPlaylist: 存储媒体URL]
    A --> C[QListWidget: 显示文件名]
    D[用户点击列表项] --> E[发送信号 currentRowChanged]
    E --> F[槽函数: m_playlist-&gt;setCurrentIndex(row)]
    F --> G[QMediaPlayer 自动播放新索引的媒体]
    G --> H[界面更新: 标题, 进度条等]

这个图展示了数据和事件是如何在两个核心组件(后台的Playlist和前台显示的ListWidget)之间流动的,确保它们的状态保持一致。


(篇幅已经很长,但我们才完成了不到一半的核心内容!接下来的自定义皮肤、数据持久化、打包发布等部分同样精彩且实用。让我们一鼓作气…)

6. 自定义皮肤:打造独一无二的UI

默认的界面太普通了,我们用QSS(QT Style Sheets)来给它化妆。QSS的语法和CSS几乎一模一样,如果你写过网页,上手会非常快。

6.1 QSS(QT样式表)语法基础

基本语法是:选择器 { 属性: 值; }

  • 选择器:可以是控件类型名(如QPushButton)、对象名(如#playButton)、类名等。
  • 属性:控制颜色、字体、边框、背景等。
  • :属性的具体设置。

6.2 【Code】为按钮和滑块设计炫酷样式

我们可以在代码里用字符串设置样式,也可以加载外部的QSS文件。这里我们先在代码里写。

MainWindow的构造函数中,添加如下代码:

// 设置应用程序的全局样式
QString styleSheet = R"(
    /* 主窗口背景 */
    QMainWindow {
        background: qlineargradient(x1:0, y1:0, x2:1, y2:1,
                                    stop:0 #667eea, stop:1 #764ba2);
        color: white;
        font-family: "Microsoft YaHei";
    }

    /* 所有QPushButton的通用样式 */
    QPushButton {
        background-color: rgba(255, 255, 255, 0.2); /* 半透明白色 */
        border: 2px solid rgba(255, 255, 255, 0.5);
        border-radius: 10px; /* 圆角 */
        color: white;
        padding: 5px 10px;
        font-size: 14px;
    }

    /* 按钮悬停效果 */
    QPushButton:hover {
        background-color: rgba(255, 255, 255, 0.3);
        border-color: rgba(255, 255, 255, 0.8);
    }

    /* 按钮按下效果 */
    QPushButton:pressed {
        background-color: rgba(255, 255, 255, 0.1);
    }

    /* 进度条样式 */
    QSlider::groove:horizontal {
        border: 1px solid #999999;
        height: 6px;
        background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #B1B1B1, stop:1 #c4c4c4);
        margin: 2px 0;
        border-radius: 3px;
    }

    QSlider::handle:horizontal {
        background: qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 #ffffff, stop:1 #e4e4e4);
        border: 1px solid #5c5c5c;
        width: 16px;
        margin: -6px 0;
        border-radius: 8px;
    }

    QSlider::sub-page:horizontal {
        background: qlineargradient(x1:0, y1:0, x2:0, y2:1, stop:0 #6aff6a, stop:1 #00b300);
        border-radius: 3px;
    }

    /* 列表控件样式 */
    QListWidget {
        background-color: rgba(0, 0, 0, 0.3);
        border: 1px solid rgba(255, 255, 255, 0.2);
        border-radius: 5px;
        color: white;
        outline: none; /* 去除选中时的虚线框 */
    }

    QListWidget::item:selected {
        background-color: rgba(255, 255, 255, 0.3);
    }
)";

this->setStyleSheet(styleSheet); // 应用样式表

这样,你的播放器瞬间就变得高大上了!有渐变背景、半透明效果、圆角按钮和自定义的进度条。

#@ 6.3 【举例】实现窗口圆角和背景模糊

要实现真正的亚克力或毛玻璃效果,需要用到一些平台相关的技巧。但在Windows上,一个简单的方法是设置窗口标志和属性。

MainWindow构造函数中,setupUi之后添加:

// 设置窗口无边框和半透明背景,为圆角做准备
setWindowFlags(Qt::FramelessWindowHint); // 无边框
setAttribute(Qt::WA_TranslucentBackground); // 背景透明

// 然后你需要一个容器QWidget(比如centralWidget)来设置圆角和背景色,而不是直接设置MainWindow。
ui->centralWidget->setStyleSheet("background: rgba(50, 50, 50, 0.8); border-radius: 15px;");

这样就能实现一个圆角窗口。更复杂的模糊背景需要调用Windows API,这里就不展开了。


(我们已经实现了美观的界面和核心功能,但一个专业的应用还需要记住用户的设置。接下来是数据持久化…)

7. 数据持久化:记住你的喜好

我们不希望用户每次打开播放器,歌单都是空的,音量都是100%。我们需要把一些信息保存到硬盘上,下次启动时再读出来。QT提供了QSettings类,它可以非常方便地读写INI格式的配置文件。

7.1 使用QSettings保存播放列表和音量

7.2 【Code】应用启动时加载上次的设置

我们在MainWindow类中重写两个函数:closeEvent(窗口关闭时触发)和readSettings(在构造函数中调用)。

mainwindow.h中声明:

protected:
    void closeEvent(QCloseEvent *event) override; // 重写关闭事件

private:
    void readSettings();  // 读配置
    void writeSettings(); // 写配置

mainwindow.cpp中实现:

// ... 其他代码 ...

void MainWindow::closeEvent(QCloseEvent *event)
{
    writeSettings(); // 在窗口关闭前,保存设置
    event->accept(); // 接受关闭事件
}

void MainWindow::readSettings()
{
    QSettings settings("MyCompany", "MyMusicPlayer"); // 组织名,应用名

    // 读取音量,如果不存在则使用默认值50
    int volume = settings.value("player/volume", 50).toInt();
    m_player->setVolume(volume);
    ui->volumeSlider->setValue(volume);

    // 读取播放列表
    QStringList recentPlaylist = settings.value("playlist/recentFiles").toStringList();
    for (const QString &filePath : recentPlaylist) {
        if (QFile::exists(filePath)) { // 检查文件是否还存在
            QUrl fileUrl = QUrl::fromLocalFile(filePath);
            m_playlist->addMedia(fileUrl);
            QFileInfo fileInfo(filePath);
            ui->playlistWidget->addItem(fileInfo.fileName());
        }
    }

    // 还可以读取窗口位置和大小
    QPoint pos = settings.value("window/position", QPoint(200, 200)).toPoint();
    QSize size = settings.value("window/size", QSize(800, 600)).toSize();
    move(pos);
    resize(size);
}

void MainWindow::writeSettings()
{
    QSettings settings("MyCompany", "MyMusicPlayer");

    // 保存音量
    settings.setValue("player/volume", m_player->volume());

    // 保存播放列表(保存文件的绝对路径)
    QStringList recentPlaylist;
    for (int i = 0; i < m_playlist->mediaCount(); ++i) {
        QUrl url = m_playlist->media(i).canonicalUrl();
        if (url.isLocalFile()) {
            recentPlaylist << url.toLocalFile();
        }
    }
    settings.setValue("playlist/recentFiles", recentPlaylist);

    // 保存窗口位置和大小
    settings.setValue("window/position", pos());
    settings.setValue("window/size", size());
}

// 不要忘记在MainWindow的构造函数中调用readSettings!
MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    // ... 之前的初始化代码 ...
    readSettings(); // 最后,读取设置
}

7.3 【举例】读写配置文件的实际过程

运行程序后,QSettings会在系统特定的位置(比如Windows的注册表或%APPDATA%/MyCompany/MyMusicPlayer.ini)创建一个配置项。你保存的播放列表路径、音量大小都会以键值对的形式存储在那里。下次启动时,程序会去同一个地方查找这些值。


(胜利在望!最后一步,也是让程序能从你的电脑走向别人电脑的关键一步:打包发布。)

8. 打包发布:从“程序”到“产品”的最后一步

在QT Creator里直接运行的程序,依赖于一大堆QT的动态链接库(DLL文件)。你不能直接把exe文件发给别人,因为别人的电脑上没有这些库。打包的目的就是把所有需要的库文件、插件都收集起来,和你的exe放在一起。

8.1 使用windeployqt工具打包

QT非常贴心地提供了一个命令行工具windeployqt,它能自动分析你的exe文件,找到所有依赖的QT库,并复制到exe所在的文件夹。

步骤:

  1. 在QT Creator中,将编译模式改为 Release
  2. 点击“构建”->“构建项目MyMusicPlayer”,生成Release版本的exe文件。
  3. 在文件管理器中,找到生成的exe文件,通常路径类似 build-MyMusicPlayer-Release/release/MyMusicPlayer.exe
  4. 将这个exe文件单独复制到一个空文件夹,比如D:/MyMusicPlayerRelease/
  5. 打开QT 5.15.2 MinGW 64-bit的命令行(开始菜单里能找到)。
  6. 切换到exe所在的目录:
    cd /d D:\MyMusicPlayerRelease
    
  7. 执行打包命令:
    windeployqt MyMusicPlayer.exe
    
  8. 工具会自动运行,拷贝一大堆DLL和文件夹(如plugins, translations)到当前目录。

8.2 解决常见的依赖问题

有时候windeployqt可能会漏掉一些非QT的库,比如音频/视频解码器。特别是对于音乐播放器,我们需要确保plugins文件夹里的mediaservice插件被正确包含。如果打包后在其他电脑上无法播放,可以手动从QT的安装目录(如QT/5.15.2/mingw81_64/plugins/mediaservice)下拷贝dsengine.dll等文件到你的发布文件夹的mediaservice子目录下。

8.3 【Mermaid图】打包发布流程图

为了让打包流程一目了然,请看下面的流程图:

在QT Creator中编译Release版本
在文件管理器中找到生成的.exe
将.exe复制到空文件夹
打开QT命令行终端
使用cd命令切换到.exe所在文件夹
执行windeployqt命令
工具自动分析依赖并拷贝文件
打包完成
得到包含所有依赖的文件夹
可使用Inno Setup等工具
制作安装程序

现在,整个D:/MyMusicPlayerRelease/文件夹就是你的播放器的绿色版了!你可以把它压缩成ZIP包发给任何人,只要他的系统(Windows)和你的编译环境(比如64位)匹配,就能直接运行!


(核心功能全部完成!但学无止境,我们可以让这个播放器变得更强大…)

9. 进阶功能拓展:让你的播放器更强大

这里提供一些思路和方向,供你继续探索。

9.1 歌词解析与显示(LRC文件)

  • 思路:解析与歌曲同名的.lrc文件。LRC文件是文本文件,格式是[分钟:秒.百分秒] 歌词
  • 实现:用QFileQTextStream读取文件,用正则表达式解析每一行。用一个QTimer定时检查当前播放位置,然后在一个QLabel上显示对应的歌词。

9.2 系统托盘图标与全局快捷键

  • 系统托盘:使用QSystemTrayIcon类。即使主窗口关闭,程序也能在托盘区运行。
  • 全局快捷键:使用第三方库如QHotkey,来实现即使播放器不是当前活动窗口,也能用快捷键(如Ctrl+Alt+P)控制播放/暂停。

9.3 音频可视化(频谱显示)

这是更高级的功能。QMediaPlayer本身不提供音频数据。你需要使用更低层的QAudioOutputQIODevice来获取原始的音频采样数据,然后通过傅里叶变换(FFT)计算出频谱,最后用QPainter在界面上画出漂亮的频谱图或波形图。


10. 总结与展望:你的QT之旅才刚刚开始

10.1 本项目知识点回顾

通过这个项目,我们实战了:

  • QT基本框架QMainWindow, 信号与槽。
  • UI设计:Qt Designer的使用,布局管理。
  • 核心功能模块QMediaPlayer, QMediaPlaylist
  • 数据存储QSettings的使用。
  • 界面美化:QSS样式表。
  • 项目发布windeployqt打包。

10.2 还能添加哪些好玩的功能?

  • 均衡器调节。
  • 主题切换(亮色/暗色)。
  • 播放模式(单曲循环、列表循环、随机播放)。
  • 从网络流媒体播放。

10.3 下一步学习路线建议

  1. 夯实C++基础:QT再强大,也是C++的库。深入理解面向对象、内存管理、模板STL,会让你用起QT来更得心应手。
  2. 学习QT的模型/视图框架:对于更复杂的列表/表格数据,QListWidget可能不够用,这时需要学习更强大的QTableView + QStandardItemModel
  3. 探索QML:对于追求更炫酷、更动态界面的应用,QT Quick(QML)是未来的方向。它是一种声明式的JavaScript-like语言,专门用于构建现代化UI。
  4. 接触网络编程:用QNetworkAccessManager开发网络应用。

恭喜你,老铁!你已经成功完成了一个QT实战项目。这篇文章超过了一万字,从想法到实现,再到打包发布,希望能为你打开QT开发的大门。记住,编程最好的学习方式就是动手去做,去踩坑,再去解决。

结语

感谢您的阅读!期待您的一键三连!欢迎指正!

在这里插入图片描述

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

【Air】

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值