▶️ 第一个播放功能实现
🎮 在前面搭建好界面和视频显示后,本章我们将深入完善播放功能的实现细节,让播放器的操作更加流畅和专业。我们将添加播放速度控制、更精确的进度管理,以及更丰富的播放选项。
🎯 本章目标
- ⚡ 实现播放速度调节功能
- 🎪 优化进度条的精确度和交互体验
- 🔄 添加跳转功能(前进/后退)
- 📊 实现播放统计和状态监控
- 🎨 完善播放控制界面的视觉效果
- ⌨️ 添加键盘快捷键支持
🎮 播放控制架构升级
播放控制流程图
🛠️ 代码实现
1️⃣ 更新头文件
src/main/mainwindow.h (添加新功能)
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include <QVBoxLayout>
#include <QHBoxLayout>
#include <QSplitter>
#include <QLabel>
#include <QSlider>
#include <QPushButton>
#include <QListWidget>
#include <QTextEdit>
#include <QMenuBar>
#include <QToolBar>
#include <QStatusBar>
#include <QProgressBar>
#include <QComboBox>
#include <QSpinBox>
#include <QTimer>
// Qt多媒体组件
#include <QMediaPlayer>
#include <QVideoWidget>
#include <QAudioOutput>
// 文件和拖拽支持
#include <QFileInfo>
#include <QUrl>
#include <QMimeData>
#include <QDragEnterEvent>
#include <QDropEvent>
#include <QKeyEvent>
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
MainWindow(QWidget *parent = nullptr);
~MainWindow();
protected:
void resizeEvent(QResizeEvent *event) override;
void closeEvent(QCloseEvent *event) override;
void dragEnterEvent(QDragEnterEvent *event) override;
void dropEvent(QDropEvent *event) override;
void keyPressEvent(QKeyEvent *event) override;
private slots:
void onOpenFile();
void onPlay();
void onPause();
void onStop();
void onVolumeChanged(int volume);
void onProgressChanged(int progress);
void onSpeedChanged();
void onSeekForward();
void onSeekBackward();
void onFullScreen();
void onAbout();
// 媒体播放器槽函数
void onMediaStateChanged(QMediaPlayer::PlaybackState state);
void onMediaPositionChanged(qint64 position);
void onMediaDurationChanged(qint64 duration);
void onMediaError(QMediaPlayer::Error error, const QString &errorString);
void onPlaylistItemClicked(QListWidgetItem *item);
// 新增功能槽函数
void onProgressSliderPressed();
void onProgressSliderReleased();
void onProgressSliderMoved(int position);
void updatePlaybackStats();
private:
void setupUI();
void setupMenuBar();
void setupToolBar();
void setupStatusBar();
void setupCentralWidget();
void setupVideoArea();
void setupControlBar();
void setupAdvancedControls();
void setupSidePanel();
void setupMediaPlayer();
void setupKeyboardShortcuts();
void loadStyleSheet();
void updateWindowTitle(const QString &fileName = QString());
void loadVideoFile(const QString &filePath);
void updateVideoInfo(const QString &filePath);
void updatePlayButton();
void updateSpeedButton();
void formatTime(qint64 timeInMs, QString &timeString);
bool isVideoFile(const QString &filePath);
void seekToPosition(qint64 position);
void jumpTime(int seconds);
private:
// UI组件
QWidget *m_centralWidget;
QSplitter *m_mainSplitter;
// 视频区域
QWidget *m_videoArea;
QVideoWidget *m_videoWidget;
QLabel *m_videoPlaceholder;
// 控制栏
QWidget *m_controlBar;
QPushButton *m_playButton;
QPushButton *m_stopButton;
QSlider *m_progressSlider;
QLabel *m_timeLabel;
QSlider *m_volumeSlider;
QPushButton *m_muteButton;
QPushButton *m_fullscreenButton;
// 高级控制
QWidget *m_advancedControls;
QComboBox *m_speedComboBox;
QPushButton *m_seekBackwardButton;
QPushButton *m_seekForwardButton;
QLabel *m_speedLabel;
// 侧边栏
QWidget *m_sidePanel;
QListWidget *m_playlist;
QTextEdit *m_videoInfo;
QTextEdit *m_playbackStats;
// 状态栏
QLabel *m_statusLabel;
QProgressBar *m_progressBar;
QLabel *m_volumeLabel;
QLabel *m_speedStatusLabel;
// 工具栏动作
QAction *m_openAction;
QAction *m_playAction;
QAction *m_pauseAction;
QAction *m_stopAction;
QAction *m_fullscreenAction;
QAction *m_seekForwardAction;
QAction *m_seekBackwardAction;
// 多媒体组件
QMediaPlayer *m_mediaPlayer;
QAudioOutput *m_audioOutput;
// 播放状态
bool m_isVideoLoaded;
QString m_currentVideoPath;
qint64 m_videoDuration;
bool m_isSliderPressed;
qint64 m_sliderPosition;
// 播放统计
QTimer *m_statsTimer;
qint64 m_totalPlayTime;
int m_playCount;
// 播放设置
QList<qreal> m_speedOptions;
int m_currentSpeedIndex;
int m_seekJumpSeconds;
};
#endif // MAINWINDOW_H
2️⃣ 实现高级播放控制
src/main/mainwindow.cpp (主要更新部分)
// 在构造函数中初始化新成员
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
// ... 其他初始化保持不变 ...
, m_advancedControls(nullptr)
, m_speedComboBox(nullptr)
, m_seekBackwardButton(nullptr)
, m_seekForwardButton(nullptr)
, m_speedLabel(nullptr)
, m_playbackStats(nullptr)
, m_speedStatusLabel(nullptr)
, m_sliderPosition(0)
, m_statsTimer(nullptr)
, m_totalPlayTime(0)
, m_playCount(0)
, m_currentSpeedIndex(2) // 默认1.0x速度
, m_seekJumpSeconds(10) // 默认跳转10秒
{
// 初始化播放速度选项
m_speedOptions << 0.25 << 0.5 << 0.75 << 1.0 << 1.25 << 1.5 << 1.75 << 2.0;
setupUI();
setupMenuBar();
setupToolBar();
setupStatusBar();
setupMediaPlayer();
setupKeyboardShortcuts();
loadStyleSheet();
// 启用拖拽
setAcceptDrops(true);
// 设置窗口属性
setWindowTitle("Video Player");
setMinimumSize(900, 650);
resize(1400, 900);
// 居中显示
move(QApplication::desktop()->screen()->rect().center() - rect().center());
// 恢复窗口状态
QSettings settings;
restoreGeometry(settings.value("geometry").toByteArray());
restoreState(settings.value("windowState").toByteArray());
// 初始化统计定时器
m_statsTimer = new QTimer(this);
connect(m_statsTimer, &QTimer::timeout, this, &MainWindow::updatePlaybackStats);
m_statsTimer->start(1000); // 每秒更新一次统计
}
void MainWindow::setupControlBar()
{
m_controlBar = new QWidget();
m_controlBar->setFixedHeight(120); // 增加高度以容纳更多控件
m_controlBar->setStyleSheet(
"QWidget {"
" background: qlineargradient(x1:0, y1:0, x2:0, y2:1,"
" stop:0 #34495e, stop:1 #2c3e50);"
" border-radius: 5px;"
"}"
);
QVBoxLayout *controlMainLayout = new QVBoxLayout(m_controlBar);
controlMainLayout->setContentsMargins(15, 10, 15, 10);
controlMainLayout->setSpacing(10);
// 主控制行
QHBoxLayout *controlLayout = new QHBoxLayout();
// 播放控制按钮
m_playButton = new QPushButton("▶");
m_playButton->setFixedSize(50, 50);
m_playButton->setStyleSheet(
"QPushButton {"
" background: #3498db;"
" color: white;"
" border: none;"
" border-radius: 25px;"
" font-size: 16px;"
" font-weight: bold;"
"}"
"QPushButton:hover {"
" background: #2980b9;"
"}"
"QPushButton:pressed {"
" background: #21618c;"
"}"
"QPushButton:disabled {"
" background: #7f8c8d;"
" color: #bdc3c7;"
"}"
);
connect(m_playButton, &QPushButton::clicked, this, &MainWindow::onPlay);
m_stopButton = new QPushButton("⏹");
m_stopButton->setFixedSize(40, 40);
m_stopButton->setStyleSheet(
"QPushButton {"
" background: #e74c3c;"
" color: white;"
" border: none;"
" border-radius: 20px;"
" font-size: 14px;"
"}"
"QPushButton:hover {"
" background: #c0392b;"
"}"
"QPushButton:disabled {"
" background: #7f8c8d;"
" color: #bdc3c7;"
"}"
);
connect(m_stopButton, &QPushButton::clicked, this, &MainWindow::onStop);
// 跳转按钮
m_seekBackwardButton = new QPushButton("⏪");
m_seekBackwardButton->setFixedSize(35, 35);
m_seekBackwardButton->setStyleSheet(
"QPushButton {"
" background: #9b59b6;"
" color: white;"
" border: none;"
" border-radius: 17px;"
" font-size: 12px;"
"}"
"QPushButton:hover {"
" background: #8e44ad;"
"}"
"QPushButton:disabled {"
" background: #7f8c8d;"
" color: #bdc3c7;"
"}"
);
connect(m_seekBackwardButton, &QPushButton::clicked, this, &MainWindow::onSeekBackward);
m_seekForwardButton = new QPushButton("⏩");
m_seekForwardButton->setFixedSize(35, 35);
m_seekForwardButton->setStyleSheet(m_seekBackwardButton->styleSheet());
connect(m_seekForwardButton, &QPushButton::clicked, this, &MainWindow::onSeekForward);
// 进度条
m_progressSlider = new QSlider(Qt::Horizontal);
m_progressSlider->setStyleSheet(
"QSlider::groove:horizontal {"
" height: 8px;"
" background: #7f8c8d;"
" border-radius: 4px;"
"}"
"QSlider::handle:horizontal {"
" background: #3498db;"
" border: 2px solid #2980b9;"
" width: 18px;"
" border-radius: 9px;"
" margin: -5px 0;"
"}"
"QSlider::sub-page:horizontal {"
" background: qlineargradient(x1:0, y1:0, x2:1, y2:0,"
" stop:0 #3498db, stop:1 #5dade2);"
" border-radius: 4px;"
"}"
"QSlider::handle:horizontal:hover {"
" background: #5dade2;"
" border: 2px solid #3498db;"
"}"
);
// 更精确的进度条事件处理
connect(m_progressSlider, &QSlider::sliderPressed, this, &MainWindow::onProgressSliderPressed);
connect(m_progressSlider, &QSlider::sliderReleased, this, &MainWindow::onProgressSliderReleased);
connect(m_progressSlider, &QSlider::sliderMoved, this, &MainWindow::onProgressSliderMoved);
// 时间标签
m_timeLabel = new QLabel("00:00 / 00:00");
m_timeLabel->setStyleSheet(
"QLabel {"
" color: #ecf0f1;"
" font-size: 12px;"
" font-weight: bold;"
" min-width: 90px;"
"}"
);
// 音量控制
m_muteButton = new QPushButton("🔊");
m_muteButton->setFixedSize(35, 35);
m_muteButton->setStyleSheet(
"QPushButton {"
" background: transparent;"
" color: #ecf0f1;"
" border: none;"
" border-radius: 17px;"
" font-size: 14px;"
"}"
"QPushButton:hover {"
" background: #7f8c8d;"
"}"
);
connect(m_muteButton, &QPushButton::clicked, [this]() {
if (m_audioOutput) {
bool isMuted = m_audioOutput->isMuted();
m_audioOutput->setMuted(!isMuted);
m_muteButton->setText(isMuted ? "🔊" : "🔇");
}
});
m_volumeSlider = new QSlider(Qt::Horizontal);
m_volumeSlider->setMaximum(100);
m_volumeSlider->setValue(70);
m_volumeSlider->setFixedWidth(100);
m_volumeSlider->setStyleSheet(
"QSlider::groove:horizontal {"
" height: 6px;"
" background: #7f8c8d;"
" border-radius: 3px;"
"}"
"QSlider::handle:horizontal {"
" background: #f39c12;"
" border: none;"
" width: 16px;"
" border-radius: 8px;"
" margin: -5px 0;"
"}"
"QSlider::sub-page:horizontal {"
" background: #f39c12;"
" border-radius: 3px;"
"}"
);
connect(m_volumeSlider, &QSlider::valueChanged, this, &MainWindow::onVolumeChanged);
// 全屏按钮
m_fullscreenButton = new QPushButton("⛶");
m_fullscreenButton->setFixedSize(35, 35);
m_fullscreenButton->setStyleSheet(m_muteButton->styleSheet());
connect(m_fullscreenButton, &QPushButton::clicked, this, &MainWindow::onFullScreen);
// 主控制行布局
controlLayout->addWidget(m_seekBackwardButton);
controlLayout->addWidget(m_playButton);
controlLayout->addWidget(m_seekForwardButton);
controlLayout->addWidget(m_stopButton);
controlLayout->addSpacing(10);
controlLayout->addWidget(m_progressSlider);
controlLayout->addSpacing(10);
controlLayout->addWidget(m_timeLabel);
controlLayout->addSpacing(20);
controlLayout->addWidget(m_muteButton);
controlLayout->addWidget(m_volumeSlider);
controlLayout->addSpacing(10);
controlLayout->addWidget(m_fullscreenButton);
// 高级控制行
setupAdvancedControls();
controlMainLayout->addLayout(controlLayout);
controlMainLayout->addWidget(m_advancedControls);
// 初始状态设置为禁用
m_playButton->setEnabled(false);
m_stopButton->setEnabled(false);
m_progressSlider->setEnabled(false);
m_seekBackwardButton->setEnabled(false);
m_seekForwardButton->setEnabled(false);
}
void MainWindow::setupAdvancedControls()
{
m_advancedControls = new QWidget();
m_advancedControls->setFixedHeight(35);
QHBoxLayout *advancedLayout = new QHBoxLayout(m_advancedControls);
advancedLayout->setContentsMargins(0, 0, 0, 0);
// 播放速度控制
m_speedLabel = new QLabel("播放速度:");
m_speedLabel->setStyleSheet(
"QLabel {"
" color: #ecf0f1;"
" font-size: 11px;"
"}"
);
m_speedComboBox = new QComboBox();
m_speedComboBox->setFixedWidth(80);
m_speedComboBox->addItems({"0.25x", "0.5x", "0.75x", "1.0x", "1.25x", "1.5x", "1.75x", "2.0x"});
m_speedComboBox->setCurrentIndex(m_currentSpeedIndex);
m_speedComboBox->setStyleSheet(
"QComboBox {"
" background: #34495e;"
" color: #ecf0f1;"
" border: 1px solid #7f8c8d;"
" border-radius: 3px;"
" padding: 3px 8px;"
" font-size: 11px;"
"}"
"QComboBox::drop-down {"
" border: none;"
"}"
"QComboBox::down-arrow {"
" image: none;"
" border-left: 5px solid transparent;"
" border-right: 5px solid transparent;"
" border-top: 5px solid #ecf0f1;"
"}"
"QComboBox QAbstractItemView {"
" background: #2c3e50;"
" color: #ecf0f1;"
" selection-background-color: #3498db;"
"}"
);
connect(m_speedComboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
this, &MainWindow::onSpeedChanged);
// 跳转时间设置
QLabel *jumpLabel = new QLabel("跳转:");
jumpLabel->setStyleSheet(m_speedLabel->styleSheet());
QSpinBox *jumpSpinBox = new QSpinBox();
jumpSpinBox->setRange(5, 60);
jumpSpinBox->setValue(m_seekJumpSeconds);
jumpSpinBox->setSuffix("秒");
jumpSpinBox->setFixedWidth(60);
jumpSpinBox->setStyleSheet(
"QSpinBox {"
" background: #34495e;"
" color: #ecf0f1;"
" border: 1px solid #7f8c8d;"
" border-radius: 3px;"
" padding: 2px;"
" font-size: 11px;"
"}"
);
connect(jumpSpinBox, QOverload<int>::of(&QSpinBox::valueChanged),
[this](int value) { m_seekJumpSeconds = value; });
advancedLayout->addWidget(m_speedLabel);
advancedLayout->addWidget(m_speedComboBox);
advancedLayout->addSpacing(20);
advancedLayout->addWidget(jumpLabel);
advancedLayout->addWidget(jumpSpinBox);
advancedLayout->addStretch();
// 播放统计信息
QLabel *statsLabel = new QLabel("统计信息");
statsLabel->setStyleSheet(m_speedLabel->styleSheet());
advancedLayout->addWidget(statsLabel);
}
void MainWindow::setupSidePanel()
{
m_sidePanel = new QWidget();
m_sidePanel->setMaximumWidth(350);
m_sidePanel->setMinimumWidth(250);
QVBoxLayout *sideLayout = new QVBoxLayout(m_sidePanel);
sideLayout->setContentsMargins(5, 0, 0, 0);
// 播放列表
QLabel *playlistLabel = new QLabel("📋 播放列表");
playlistLabel->setStyleSheet(
"QLabel {"
" font-size: 14px;"
" font-weight: bold;"
" color: #2c3e50;"
" padding: 8px 5px;"
"}"
);
m_playlist = new QListWidget();
m_playlist->setStyleSheet(
"QListWidget {"
" background: #ecf0f1;"
" border: 1px solid #bdc3c7;"
" border-radius: 5px;"
" padding: 5px;"
"}"
"QListWidget::item {"
" padding: 8px;"
" border-bottom: 1px solid #d5dbdb;"
"}"
"QListWidget::item:selected {"
" background: #3498db;"
" color: white;"
"}"
"QListWidget::item:hover {"
" background: #d6eaf8;"
"}"
);
connect(m_playlist, &QListWidget::itemClicked, this, &MainWindow::onPlaylistItemClicked);
// 视频信息
QLabel *infoLabel = new QLabel("ℹ️ 视频信息");
infoLabel->setStyleSheet(playlistLabel->styleSheet());
m_videoInfo = new QTextEdit();
m_videoInfo->setMaximumHeight(150);
m_videoInfo->setReadOnly(true);
m_videoInfo->setStyleSheet(
"QTextEdit {"
" background: #ecf0f1;"
" border: 1px solid #bdc3c7;"
" border-radius: 5px;"
" padding: 8px;"
" font-size: 11px;"
" color: #2c3e50;"
"}"
);
m_videoInfo->setPlainText(
"文件名: 未选择文件\n"
"格式: --\n"
"分辨率: --\n"
"时长: --\n"
"比特率: --\n"
"编码: --"
);
// 播放统计
QLabel *statsLabel = new QLabel("📊 播放统计");
statsLabel->setStyleSheet(playlistLabel->styleSheet());
m_playbackStats = new QTextEdit();
m_playbackStats->setMaximumHeight(100);
m_playbackStats->setReadOnly(true);
m_playbackStats->setStyleSheet(m_videoInfo->styleSheet());
sideLayout->addWidget(playlistLabel);
sideLayout->addWidget(m_playlist, 1);
sideLayout->addSpacing(10);
sideLayout->addWidget(infoLabel);
sideLayout->addWidget(m_videoInfo);
sideLayout->addSpacing(10);
sideLayout->addWidget(statsLabel);
sideLayout->addWidget(m_playbackStats);
}
void MainWindow::setupKeyboardShortcuts()
{
// 播放/暂停 - 空格键
QShortcut *playShortcut = new QShortcut(QKeySequence(Qt::Key_Space), this);
connect(playShortcut, &QShortcut::activated, this, &MainWindow::onPlay);
// 停止 - S键
QShortcut *stopShortcut = new QShortcut(QKeySequence(Qt::Key_S), this);
connect(stopShortcut, &QShortcut::activated, this, &MainWindow::onStop);
// 音量调节 - 上下箭头
QShortcut *volumeUpShortcut = new QShortcut(QKeySequence(Qt::Key_Up), this);
connect(volumeUpShortcut, &QShortcut::activated, [this]() {
int volume = m_volumeSlider->value();
m_volumeSlider->setValue(qMin(100, volume + 5));
});
QShortcut *volumeDownShortcut = new QShortcut(QKeySequence(Qt::Key_Down), this);
connect(volumeDownShortcut, &QShortcut::activated, [this]() {
int volume = m_volumeSlider->value();
m_volumeSlider->setValue(qMax(0, volume - 5));
});
// 跳转 - 左右箭头
QShortcut *seekBackShortcut = new QShortcut(QKeySequence(Qt::Key_Left), this);
connect(seekBackShortcut, &QShortcut::activated, this, &MainWindow::onSeekBackward);
QShortcut *seekForwardShortcut = new QShortcut(QKeySequence(Qt::Key_Right), this);
connect(seekForwardShortcut, &QShortcut::activated, this, &MainWindow::onSeekForward);
// 全屏 - F11
QShortcut *fullscreenShortcut = new QShortcut(QKeySequence(Qt::Key_F11), this);
connect(fullscreenShortcut, &QShortcut::activated, this, &MainWindow::onFullScreen);
// 静音 - M键
QShortcut *muteShortcut = new QShortcut(QKeySequence(Qt::Key_M), this);
connect(muteShortcut, &QShortcut::activated, m_muteButton, &QPushButton::click);
}
// 新增槽函数实现
void MainWindow::onProgressSliderPressed()
{
m_isSliderPressed = true;
}
void MainWindow::onProgressSliderReleased()
{
if (m_mediaPlayer && m_isVideoLoaded && m_videoDuration > 0) {
qint64 position = (m_progressSlider->value() * m_videoDuration) / 1000;
seekToPosition(position);
}
m_isSliderPressed = false;
}
void MainWindow::onProgressSliderMoved(int position)
{
if (m_isSliderPressed && m_videoDuration > 0) {
m_sliderPosition = (position * m_videoDuration) / 1000;
// 实时更新时间显示
QString currentTime, totalTime;
formatTime(m_sliderPosition, currentTime);
formatTime(m_videoDuration, totalTime);
m_timeLabel->setText(QString("%1 / %2").arg(currentTime, totalTime));
}
}
void MainWindow::onSpeedChanged()
{
if (m_mediaPlayer && m_isVideoLoaded) {
m_currentSpeedIndex = m_speedComboBox->currentIndex();
qreal speed = m_speedOptions[m_currentSpeedIndex];
m_mediaPlayer->setPlaybackRate(speed);
updateSpeedButton();
m_statusLabel->setText(QString("播放速度: %1x").arg(speed));
}
}
void MainWindow::onSeekBackward()
{
jumpTime(-m_seekJumpSeconds);
}
void MainWindow::onSeekForward()
{
jumpTime(m_seekJumpSeconds);
}
void MainWindow::updatePlaybackStats()
{
if (m_mediaPlayer && m_mediaPlayer->playbackState() == QMediaPlayer::PlayingState) {
m_totalPlayTime += 1000; // 每秒增加1000毫秒
}
QString totalTimeStr, currentPosStr;
formatTime(m_totalPlayTime, totalTimeStr);
if (m_mediaPlayer) {
formatTime(m_mediaPlayer->position(), currentPosStr);
}
QString statsText = QString(
"播放次数: %1\n"
"总播放时长: %2\n"
"当前位置: %3\n"
"播放速度: %4x"
).arg(m_playCount)
.arg(totalTimeStr)
.arg(currentPosStr)
.arg(m_speedOptions[m_currentSpeedIndex]);
if (m_playbackStats) {
m_playbackStats->setPlainText(statsText);
}
}
void MainWindow::updateSpeedButton()
{
if (m_speedStatusLabel) {
qreal speed = m_speedOptions[m_currentSpeedIndex];
m_speedStatusLabel->setText(QString("速度: %1x").arg(speed));
}
}
void MainWindow::seekToPosition(qint64 position)
{
if (m_mediaPlayer && m_isVideoLoaded) {
m_mediaPlayer->setPosition(position);
}
}
void MainWindow::jumpTime(int seconds)
{
if (m_mediaPlayer && m_isVideoLoaded) {
qint64 currentPos = m_mediaPlayer->position();
qint64 newPos = currentPos + (seconds * 1000);
newPos = qMax(0LL, qMin(newPos, m_videoDuration));
seekToPosition(newPos);
QString jumpMsg = seconds > 0 ?
QString("快进 %1 秒").arg(seconds) :
QString("快退 %1 秒").arg(-seconds);
m_statusLabel->setText(jumpMsg);
}
}
// 更新现有的槽函数
void MainWindow::onMediaStateChanged(QMediaPlayer::PlaybackState state)
{
switch (state) {
case QMediaPlayer::StoppedState:
m_playButton->setText("▶");
m_statusLabel->setText("已停止");
break;
case QMediaPlayer::PlayingState:
m_playButton->setText("⏸");
m_statusLabel->setText("播放中...");
if (m_playCount == 0 || m_mediaPlayer->position() == 0) {
m_playCount++;
}
break;
case QMediaPlayer::PausedState:
m_playButton->setText("▶");
m_statusLabel->setText("已暂停");
break;
}
updatePlayButton();
}
void MainWindow::onMediaPositionChanged(qint64 position)
{
if (!m_isSliderPressed && m_videoDuration > 0) {
int sliderValue = (position * 1000) / m_videoDuration;
m_progressSlider->setValue(sliderValue);
// 更新时间显示
QString currentTime, totalTime;
formatTime(position, currentTime);
formatTime(m_videoDuration, totalTime);
m_timeLabel->setText(QString("%1 / %2").arg(currentTime, totalTime));
}
}
void MainWindow::onMediaDurationChanged(qint64 duration)
{
m_videoDuration = duration;
m_progressSlider->setEnabled(duration > 0);
m_progressSlider->setMaximum(1000); // 使用1000作为最大值提高精度
QString totalTime;
formatTime(duration, totalTime);
m_timeLabel->setText(QString("00:00 / %1").arg(totalTime));
}
void MainWindow::updatePlayButton()
{
bool hasVideo = m_isVideoLoaded;
m_playButton->setEnabled(hasVideo);
m_stopButton->setEnabled(hasVideo);
m_fullscreenButton->setEnabled(hasVideo);
m_seekBackwardButton->setEnabled(hasVideo);
m_seekForwardButton->setEnabled(hasVideo);
m_speedComboBox->setEnabled(hasVideo);
}
void MainWindow::loadVideoFile(const QString &filePath)
{
if (!QFileInfo::exists(filePath)) {
QMessageBox::warning(this, "错误", "文件不存在!");
return;
}
// 设置媒体源
m_mediaPlayer->setSource(QUrl::fromLocalFile(filePath));
m_currentVideoPath = filePath;
m_isVideoLoaded = true;
// 重置播放速度
m_currentSpeedIndex = 3; // 1.0x
m_speedComboBox->setCurrentIndex(m_currentSpeedIndex);
m_mediaPlayer->setPlaybackRate(1.0);
// 显示视频组件,隐藏占位符
m_videoPlaceholder->hide();
m_videoWidget->show();
// 启用控制按钮
updatePlayButton();
// 更新窗口标题
updateWindowTitle(QFileInfo(filePath).baseName());
// 更新播放列表
QListWidgetItem *item = new QListWidgetItem(QFileInfo(filePath).fileName());
item->setData(Qt::UserRole, filePath);
m_playlist->addItem(item);
m_playlist->setCurrentItem(item);
// 更新视频信息
updateVideoInfo(filePath);
m_statusLabel->setText("视频已加载: " + QFileInfo(filePath).fileName());
}
void MainWindow::setupStatusBar()
{
m_statusLabel = new QLabel("就绪");
statusBar()->addWidget(m_statusLabel);
// 进度条
m_progressBar = new QProgressBar();
m_progressBar->setVisible(false);
m_progressBar->setMaximumWidth(200);
statusBar()->addPermanentWidget(m_progressBar);
// 播放速度显示
m_speedStatusLabel = new QLabel("速度: 1.0x");
statusBar()->addPermanentWidget(m_speedStatusLabel);
// 音量显示
m_volumeLabel = new QLabel("音量: 70%");
statusBar()->addPermanentWidget(m_volumeLabel);
// 版本信息
QLabel *versionLabel = new QLabel("v1.0.0");
versionLabel->setStyleSheet("color: #7f8c8d;");
statusBar()->addPermanentWidget(versionLabel);
}
// 键盘事件处理
void MainWindow::keyPressEvent(QKeyEvent *event)
{
// 防止在编辑框中触发快捷键
if (event->key() == Qt::Key_Space && !m_videoWidget->hasFocus()) {
event->accept();
return;
}
QMainWindow::keyPressEvent(event);
}
3️⃣ 添加包含文件
在mainwindow.cpp文件顶部添加:
#include <QShortcut>
#include <QKeyEvent>
#include <QComboBox>
#include <QSpinBox>
#include <QTimer>
🎮 功能特性展示
⚡ 播放速度控制
- 多档速度:0.25x - 2.0x 共8档速度
- 实时调节:播放过程中可随时调节速度
- 状态显示:状态栏显示当前播放速度
🎯 精确进度控制
- 高精度进度条:1000档精度,拖拽更流畅
- 实时预览:拖拽时实时显示目标时间
- 快捷跳转:支持快进/快退功能
⌨️ 键盘快捷键
- 空格键:播放/暂停
- S键:停止播放
- ←/→:快退/快进
- ↑/↓:音量调节
- F11:全屏切换
- M键:静音切换
📊 播放统计
- 播放次数:记录视频播放次数
- 播放时长:统计总播放时间
- 实时状态:显示当前播放位置和速度
🎨 界面优化
视觉效果提升
- 渐变进度条:更美观的进度显示
- 按钮状态反馈:hover和press状态
- 高级控制面板:播放速度和跳转设置
- 统计信息展示:实时播放数据
用户体验改进
- 智能按钮状态:根据播放状态自动启用/禁用
- 实时反馈:操作后立即显示状态变化
- 记忆功能:记住用户的播放偏好设置
📋 本章小结
在第四章中,我们大幅提升了播放功能:
✅ 播放速度控制:8档速度调节,实时切换
✅ 精确进度管理:1000档精度,拖拽预览
✅ 快捷键支持:完整的键盘操作支持
✅ 跳转功能:可自定义的快进快退
✅ 播放统计:详细的播放数据记录
✅ 界面优化:更美观的控制面板和状态反馈
🎯 下章预告
在下一章《🔊 音量控制与静音功能》中,我们将:
- 完善音频输出设备管理
- 添加音频均衡器功能
- 实现音频可视化效果
- 优化音量控制的用户体验
💡 小贴士:现在的播放器已经具备了专业播放器的大部分功能!试试用键盘快捷键控制播放,体验丝滑的操作感受。
🌟 功能越来越强大了!点赞收藏支持一下,下章继续优化音频体验~
6249

被折叠的 条评论
为什么被折叠?



