Linux->ubuntu22.04->Qt5.9.0
具体效果:
实现的功能:播放歌曲、切换歌曲,进度条拖动、滚动歌词、循环单曲随机播放、可保存的喜欢、快进快退、歌曲的倍速播放、专辑封面滚轮动画、大背景图切换、播放历史喜欢列表和播放列表、音量控制、播放歌曲MV。
默认背景:
播放效果:
歌曲列表:
MV播放效果:
使用到的UI:
UI布局(都说丑丑的但我嘴硬并不承认),参考哈
具体实现:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include <QSlider>
#include <QLabel>
#include <QString>
#include <QTimer>
#include <QMap>
#include <QTableWidget>
#include <vector>
#include <random>
#include <QPixmap>
#include <QPropertyAnimation>
#include <QTransform>
#include <QPainter>
#include <QResizeEvent>
#include <QGraphicsBlurEffect>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>
#include <QPaintEvent>
#include <QProcess>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
protected:
void resizeEvent(QResizeEvent *event) override;
void mousePressEvent(QMouseEvent *event) override;
void paintEvent(QPaintEvent *event) override;
public:
void prepareCircularPixmap();
void rotateImage();
explicit Widget(QWidget *parent = nullptr);
~Widget();
void updateLikeButtonVisibility();
void loadLikeSongList();
void updateLikeSongList();
void mplayerInit();
void my_search_dir();
void changeSong(int current_song);
void requestCurrentTime();
void loadLyrics(const QString &songName);
void update_lyrics_display(int currentTime);
void pauseTimer();
void resumeTimer();
void updateSongNameLabel(const QString &songName);
void updateSongerNameLabel(const QString &songerName);
void populateSongList();
enum PlaybackMode { Normal, SingleLoop, Shuffle };
void playCurrentSongAgain();
void playRandomSong();
void nextSong();
void updateCurrentSongDisplay();
void updateBackground();
void playVideoWithGStreamer(const QString &videoPath);
void updateHistoryTable(const QString &songName);
void setupHistoryTable();
private slots:
void on_nextBtn_clicked();
void on_pauseBtn_clicked();
void on_backBtn_clicked();
void set_total_time_label(int total_time);
void update_current_time(int current_time);
void sliderMoved(int position);
void sliderPressed();
void sliderReleased();
void on_songTable_doubleClicked(QTableWidgetItem* item);
void on_editBtn_pressed();
void on_likeBtn1_pressed();
void on_likeBtn2_pressed();
void setCurrentPlayingSong(const QString &name);
void processMPlayerResponse(const QString &response);
void on_likeSongListTableWidget_doubleClicked(QTableWidgetItem* item);
void setPlaybackMode(int modeIndex);
void setVolume(int volume);
void toggleVolumeSlider();
void toggleMute();
void updateVolumeButtons(int volume);
void changePlaybackSpeed(const QString& speed);
void on_playBtn_clicked();
void on_quiteBackBtn_clicked();
void on_quiteNextBtn_clicked();
signals:
void setTotalTime(int total_time);
void setCurrentTime(int current_time);
private:
Ui::Widget *ui;
QPixmap backgroundPixmap;
QPixmap totalbackgroundPixmap;
int fifo_fd;
std::vector<QString> songList;
int current_song;
int fd[2];
bool isPlaying;
int total_time;
QTimer *timer;
bool sliderIsPressed = false;
int lastSliderPosition = 0;
QString currentSongName;
float currentTime;
QMultiMap<int, QString> lyricsMap;
QString currentPlayingSong;
static void *read_mplayer_ans(void *arg);
QTimer *rotationTimer;
int rotationAngle = 0;
std::mt19937 rng;
PlaybackMode currentMode = Normal;
QPixmap circularBackgroundPixmap;
QPropertyAnimation* rotationAnimation;
void setLabelGreen(QLabel* label);
QProcess* mvProcess = nullptr;
};
#endif // WIDGET_H
//.cpp文件
#include "widget.h"
#include "ui_widget.h"
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <dirent.h>
#include <string.h>
#include <stdlib.h>
#include <QDebug>
#include <QFile>
#include <QVBoxLayout>
#include <QDir>
#include <QTime>
#include <QFont>
#include <QPalette>
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget),
currentTime(0),
total_time(0)
{
ui->setupUi(this);
this->setWindowTitle("小小凤的音乐播放器");
mplayerInit();
ui->likeBtn2->hide();
my_search_dir();
current_song = -1;
timer = new QTimer(this);
connect(timer, &QTimer::timeout, this, &Widget::requestCurrentTime);
timer->start(500);
ui->songListTabWidget->setVisible(false);
loadLikeSongList();
prepareCircularPixmap();
setupHistoryTable();
totalbackgroundPixmap.load("./song_background/background.png");
backgroundPixmap.load("./song_pic/background.png");
ui->picLabel->setPixmap(backgroundPixmap.scaled(ui->picLabel->size(), Qt::KeepAspectRatio, Qt::SmoothTransformation));
rotationAnimation = new QPropertyAnimation(ui->picLabel, "rotation");
rotationAnimation->setDuration(10000);
rotationAnimation->setStartValue(0);
rotationAnimation->setEndValue(360);
rotationAnimation->setLoopCount(-1);
rotationAnimation->setEasingCurve(QEasingCurve::Linear);
ui->setVolumeVerticalSlider->setRange(70, 100);
ui->setVolumeVerticalSlider->setValue(80);
ui->playBtn->hide(); // playBtn 默认隐藏
ui->pauseBtn->show(); // pauseBtn 默认显示
ui->historyTableWidget->setColumnCount(1); // 只有一列,用于显示歌曲名
ui->historyTableWidget->setHorizontalHeaderLabels(QStringList() << "History Played Songs");
updateVolumeButtons(ui->setVolumeVerticalSlider->value()); // 初始化按钮状态
ui->setVolumeVerticalSlider->hide();
rotationTimer = new QTimer(this);
connect(rotationTimer, &QTimer::timeout, this, &Widget::rotateImage);
rotationTimer->start(100);
// 设置 songNameLabel 字体加粗和字号
QFont songNameFont;
songNameFont.setBold(true);
songNameFont.setPointSize(20);
ui->songNameLabel->setFont(songNameFont);
// 设置 songerNameLabel 字体加粗和字号
QFont songerNameFont;
songerNameFont.setBold(true);
songerNameFont.setPointSize(18);
ui->songerNameLabel->setFont(songerNameFont);
// 字体加粗设置
QFont boldFont;
boldFont.setBold(true);
ui->backbackSongLabel->setAlignment(Qt::AlignCenter);
ui->nextnextSongLabel->setAlignment(Qt::AlignCenter);
ui->nextSongLabel->setAlignment(Qt::AlignCenter);
ui->nowSongLabel->setAlignment(Qt::AlignCenter);
ui->backSongLabel->setAlignment(Qt::AlignCenter);
ui->songNameLabel->setAlignment(Qt::AlignCenter);
ui->songerNameLabel->setAlignment(Qt::AlignCenter);
// 设置backSongLabel的特殊字体和颜色
QFont backSongFont;
backSongFont.setBold(true);
backSongFont.setPointSize(20);
QPalette redPalette;
redPalette.setColor(QPalette::WindowText, Qt::red);
ui->backSongLabel->setFont(backSongFont);
ui->backSongLabel->setPalette(redPalette);
// 其他标签的字体设置
ui->nowSongLabel->setFont(boldFont);
ui->backbackSongLabel->setFont(boldFont);
ui->nextSongLabel->setFont(boldFont);
ui->nextnextSongLabel->setFont(boldFont);
// 其他标签的字体颜色设置
setLabelGreen(ui->nowSongLabel);
setLabelGreen(ui->backbackSongLabel);
setLabelGreen(ui->nextSongLabel);
setLabelGreen(ui->nextnextSongLabel);
connect(this, &Widget::setTotalTime, this, &Widget::set_total_time_label);
connect(this, &Widget::setCurrentTime, this, &Widget::update_current_time);
connect(ui->progressBar, &QSlider::sliderPressed, this, &Widget::sliderPressed);
connect(ui->progressBar, &QSlider::sliderReleased, this, &Widget::sliderReleased);
connect(ui->progressBar, &QSlider::sliderMoved, this, &Widget::sliderMoved);
connect(ui->songTable, &QTableWidget::itemDoubleClicked, this, &Widget::on_songTable_doubleClicked);
connect(ui->likeSongListTableWidget, &QTableWidget::itemDoubleClicked, this, &Widget::on_likeSongListTableWidget_doubleClicked);
connect(ui->modeSelectionBox, SIGNAL(currentIndexChanged(int)), this, SLOT(setPlaybackMode(int)));
connect(ui->setVolumeVerticalSlider, &QSlider::valueChanged, this, &Widget::setVolume);
connect(ui->setVolumeBtn, &QPushButton::clicked, this, &Widget::toggleVolumeSlider);
connect(ui->muteBtn, &QPushButton::clicked, this, &Widget::toggleMute);
connect(ui->setVolumeVerticalSlider, &QSlider::valueChanged, this, &Widget::updateVolumeButtons);
connect(ui->playBtn, &QPushButton::clicked, this, &Widget::on_playBtn_clicked);
connect(ui->pauseBtn, &QPushButton::clicked, this, &Widget::on_pauseBtn_clicked);
connect(ui->speedComboBox, SIGNAL(currentTextChanged(const QString&)), this, SLOT(changePlaybackSpeed(const QString&)));
connect(ui->quiteBackBtn, &QPushButton::clicked, this, &Widget::on_quiteBackBtn_clicked);
connect(ui->quiteNextBtn, &QPushButton::clicked, this, &Widget::on_quiteNextBtn_clicked);
connect(ui->playMVPushButton, &QPushButton::clicked, this, [this]() {
on_pauseBtn_clicked();
QString mvFilePath = "./song_mv/" + currentPlayingSong.section('.', 0, 0).trimmed() + ".mp4";
playVideoWithGStreamer(mvFilePath);
});
}
void Widget::setupHistoryTable() {
ui->historyTableWidget->setColumnCount(1); // 只有一列
ui->historyTableWidget->setHorizontalHeaderLabels(QStringList() << "History Played Songs");
ui->historyTableWidget->horizontalHeader()->setStretchLastSection(true); // 设置列宽自适应表格宽度
ui->historyTableWidget->setEditTriggers(QAbstractItemView::NoEditTriggers); // 禁止编辑
ui->historyTableWidget->horizontalHeader()->setSectionResizeMode(QHeaderView::Stretch); // 让列宽自动调整以填满空间
}
void Widget::updateHistoryTable(const QString &songName) {
bool alreadyExists = false;
int rowCount = ui->historyTableWidget->rowCount();
for (int i = 0; i < rowCount; ++i) {
QTableWidgetItem *item = ui->historyTableWidget->item(i, 0);
if (item && item->text() == songName) {
alreadyExists = true;
break;
}
}
if (!alreadyExists) {
ui->historyTableWidget->insertRow(rowCount);
QTableWidgetItem *newItem = new QTableWidgetItem(songName);
newItem->setTextAlignment(Qt::AlignLeft | Qt::AlignVCenter);
ui->historyTableWidget->setItem(rowCount, 0, newItem);
}
}
void Widget::playVideoWithGStreamer(const QString &videoPath) {
if (mvProcess) {
mvProcess->terminate(); // 尝试终止当前进程
mvProcess->waitForFinished(); // 等待进程结束
delete mvProcess; // 删除进程对象
}