第一个播放功能

▶️ 第一个播放功能实现

🎮 在前面搭建好界面和视频显示后,本章我们将深入完善播放功能的实现细节,让播放器的操作更加流畅和专业。我们将添加播放速度控制、更精确的进度管理,以及更丰富的播放选项。

🎯 本章目标

  • ⚡ 实现播放速度调节功能
  • 🎪 优化进度条的精确度和交互体验
  • 🔄 添加跳转功能(前进/后退)
  • 📊 实现播放统计和状态监控
  • 🎨 完善播放控制界面的视觉效果
  • ⌨️ 添加键盘快捷键支持

🎮 播放控制架构升级

播放控制流程图

播放/暂停
进度拖拽
速度调节
跳转操作
用户操作
操作类型
切换播放状态
精确定位
变速播放
时间跳转
更新UI状态
同步播放位置
调整播放速率
计算目标位置
状态反馈
用户界面更新

🛠️ 代码实现

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档精度,拖拽预览
快捷键支持:完整的键盘操作支持
跳转功能:可自定义的快进快退
播放统计:详细的播放数据记录
界面优化:更美观的控制面板和状态反馈

🎯 下章预告

在下一章《🔊 音量控制与静音功能》中,我们将:

  • 完善音频输出设备管理
  • 添加音频均衡器功能
  • 实现音频可视化效果
  • 优化音量控制的用户体验

💡 小贴士:现在的播放器已经具备了专业播放器的大部分功能!试试用键盘快捷键控制播放,体验丝滑的操作感受。

🌟 功能越来越强大了!点赞收藏支持一下,下章继续优化音频体验~

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

吴纹185

扫1r呗

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

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

打赏作者

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

抵扣说明:

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

余额充值