音樂播放器

演示管理 Windows DWM (桌麵窗口管理器) 特徵、跳轉列錶、任務欄按鈕疊加和縮略圖工具欄。

Screenshot of the Music Player example

音樂播放器範例演示如何使用各種提供特徵通過 QtWinExtras 模塊。

注意: 範例使用來自 QtMultimedia 模塊的 QMediaPlayer 來播放音樂,但本文所聚焦的部分是 QtWinExtras 特徵的使用。

DWM 特徵

範例使用 Windows DWM (桌麵窗口管理器) 特徵以將窗口內容視覺集成到窗口框架,並使主窗口、音量彈齣窗口半透明和模糊。

範例基於是否啓用閤成,應用不同外觀。當閤成被啓用時,主窗口變半透明且窗口框架會擴展到客戶端區域,以使窗口內容無縫集成到窗口框架,如上所示。當閤成被禁用時,將著色顔色用作背景顔色。以下屏幕截圖闡明 Music Player 範例外觀如何當閤成被禁用時。

Screenshot of the Music Player example

各自代碼組閤擴展或重置係統框架,調節必要 QWidget 屬性,並設置適當樣式錶以達成期望外觀。

void MusicPlayer::stylize()
{
    if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8) {
        // Set styling options relevant only to Windows 7.
        if (QtWin::isCompositionEnabled()) {
            QtWin::extendFrameIntoClientArea(this, -1, -1, -1, -1);
            setAttribute(Qt::WA_TranslucentBackground, true);
            setAttribute(Qt::WA_NoSystemBackground, false);
            setStyleSheet(QStringLiteral("MusicPlayer { background: transparent; }"));
        } else {
            QtWin::resetExtendedFrame(this);
            setAttribute(Qt::WA_TranslucentBackground, false);
            setStyleSheet(QStringLiteral("MusicPlayer { background: %1; }").arg(QtWin::realColorizationColor().name()));
        }
        volumeButton->stylize();
    }
}
					

音量彈齣窗口沒有窗口框架,因此足以模糊彈齣窗口當啓用閤成時。此外,應用樣式錶能獲得遵循著色顔色的邊框。就像主窗口,當禁用閤成時,著色顔色將用作背景顔色。

void VolumeButton::stylize()
{
    if (QOperatingSystemVersion::current() < QOperatingSystemVersion::Windows8) {
        // Set styling options relevant only to Windows 7.
        if (QtWin::isCompositionEnabled()) {
            QtWin::enableBlurBehindWindow(menu);
            QString css("QMenu { border: 1px solid %1; border-radius: 2px; background: transparent; }");
            menu->setStyleSheet(css.arg(QtWin::realColorizationColor().name()));
        } else {
            QtWin::disableBlurBehindWindow(menu);
            QString css("QMenu { border: 1px solid black; background: %1; }");
            menu->setStyleSheet(css.arg(QtWin::realColorizationColor().name()));
        }
    }
}
					

範例應用程序遵守用戶閤成設置,對動態閤成改變作齣應答,且看起來是實色不管閤成是否被啓用。它完成這通過捕獲 QWinEvent::CompositionChange 和 QWinEvent::ColorizationChange 事件並相應調節其外觀。

bool MusicPlayer::event(QEvent *event)
{
    if (event->type() == QWinEvent::CompositionChange || event->type() == QWinEvent::ColorizationChange)
        stylize();
    return QWidget::event(event);
}
					
					

跳轉列錶

範例創建自定義跳轉列錶,為用戶提供對最近播放音樂文件的快速訪問。

void MusicPlayer::createJumpList()
{
    QWinJumpList jumplist;
    jumplist.recent()->setVisible(true);
}
					

要啓用應用程序跳轉列錶以展示期望的最近文件,使用以下幫手函數注冊相應文件類型。

static bool associateFileTypes()
{
    QString displayName = QGuiApplication::applicationDisplayName();
    QString filePath = QCoreApplication::applicationFilePath();
    QString fileName = QFileInfo(filePath).fileName();
    const QString key = QStringLiteral("HKEY_CURRENT_USER\\Software\\Classes\\Applications\\") + fileName;
    QSettings settings(key, QSettings::NativeFormat);
    if (settings.status() != QSettings::NoError) {
        qWarning() << "Cannot access registry key" << key;
        return false;
    }
    settings.setValue(QStringLiteral("FriendlyAppName"), displayName);
    settings.beginGroup(QStringLiteral("SupportedTypes"));
    QMimeDatabase mimeDatabase;
    const QStringList supportedMimeTypes = MusicPlayer::supportedMimeTypes();
    for (const QString &fileType : supportedMimeTypes) {
        const QStringList suffixes = mimeDatabase.mimeTypeForName(fileType).suffixes();
        for (QString suffix : suffixes) {
            suffix.prepend('.');
            settings.setValue(suffix, QString());
        }
    }
    settings.endGroup();
    settings.beginGroup(QStringLiteral("shell"));
    settings.beginGroup(QStringLiteral("open"));
    settings.setValue(QStringLiteral("FriendlyAppName"), displayName);
    settings.beginGroup(QStringLiteral("Command"));
    settings.setValue(QStringLiteral("."),
                      u'"' + QDir::toNativeSeparators(filePath) + QStringLiteral("\" \"%1\""));
    return true;
}
					
					

任務欄疊加和進度

範例使用 Windows 任務欄為 2 件事;設置錶示當前音樂迴放狀態的疊加圖標,和在任務欄按鈕指示迴放進度。

Screenshot of the Music Player taskbar

以下代碼片段展示任務欄按鈕是如何準備的。

為使任務欄和縮略圖工具欄工作,必須設置本機窗口句柄通過傳遞實例化的 QWindow to QWinTaskbarButton::setWindow() or QWinThumbnailToolBar::setWindow() ,分彆。此實例的創建是在過程 QWidget::show() and can be retrieved by calling QWidget::windowHandle() afterwards. We override QWidget::showEvent() for this purpose:

void MusicPlayer::showEvent(QShowEvent *event)
{
    QWidget::showEvent(event);
    if (!taskbarButton->window()) {
        auto window = windowHandle();
        taskbarButton->setWindow(window);
        thumbnailToolBar->setWindow(window);
    }
}
					

迴放進度直接有綫到任務欄進度指示器,通過信號和槽。

void MusicPlayer::createTaskbar()
{
    taskbarButton = new QWinTaskbarButton(this);
    taskbarProgress = taskbarButton->progress();
    connect(positionSlider, &QAbstractSlider::valueChanged, taskbarProgress, &QWinTaskbarProgress::setValue);
    connect(positionSlider, &QAbstractSlider::rangeChanged, taskbarProgress, &QWinTaskbarProgress::setRange);
    connect(&mediaPlayer, &QMediaPlayer::stateChanged, this, &MusicPlayer::updateTaskbar);
}
					

會更新疊加圖標和進度指示器,每當音樂迴放狀態改變時。

void MusicPlayer::updateTaskbar()
{
    switch (mediaPlayer.state()) {
    case QMediaPlayer::PlayingState:
        taskbarButton->setOverlayIcon(style()->standardIcon(QStyle::SP_MediaPlay));
        taskbarProgress->show();
        taskbarProgress->resume();
        break;
    case QMediaPlayer::PausedState:
        taskbarButton->setOverlayIcon(style()->standardIcon(QStyle::SP_MediaPause));
        taskbarProgress->show();
        taskbarProgress->pause();
        break;
    case QMediaPlayer::StoppedState:
        taskbarButton->setOverlayIcon(style()->standardIcon(QStyle::SP_MediaStop));
        taskbarProgress->hide();
        break;
    }
}
					
					

縮略圖工具欄

Screenshot of the Music Player thumbnail

Windows 縮略圖工具欄用於提供基本音樂迴放控件。這些控件可用於控製應用程序,不必激活應用程序。

void MusicPlayer::createThumbnailToolBar()
{
    thumbnailToolBar = new QWinThumbnailToolBar(this);
    playToolButton = new QWinThumbnailToolButton(thumbnailToolBar);
    playToolButton->setEnabled(false);
    playToolButton->setToolTip(tr("Play"));
    playToolButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay));
    connect(playToolButton, &QWinThumbnailToolButton::clicked, this, &MusicPlayer::togglePlayback);
    forwardToolButton = new QWinThumbnailToolButton(thumbnailToolBar);
    forwardToolButton->setEnabled(false);
    forwardToolButton->setToolTip(tr("Fast forward"));
    forwardToolButton->setIcon(style()->standardIcon(QStyle::SP_MediaSeekForward));
    connect(forwardToolButton, &QWinThumbnailToolButton::clicked, this, &MusicPlayer::seekForward);
    backwardToolButton = new QWinThumbnailToolButton(thumbnailToolBar);
    backwardToolButton->setEnabled(false);
    backwardToolButton->setToolTip(tr("Rewind"));
    backwardToolButton->setIcon(style()->standardIcon(QStyle::SP_MediaSeekBackward));
    connect(backwardToolButton, &QWinThumbnailToolButton::clicked, this, &MusicPlayer::seekBackward);
    thumbnailToolBar->addButton(backwardToolButton);
    thumbnailToolBar->addButton(playToolButton);
    thumbnailToolBar->addButton(forwardToolButton);
    connect(&mediaPlayer, &QMediaPlayer::positionChanged, this, &MusicPlayer::updateThumbnailToolBar);
    connect(&mediaPlayer, &QMediaPlayer::durationChanged, this, &MusicPlayer::updateThumbnailToolBar);
    connect(&mediaPlayer, &QMediaPlayer::stateChanged, this, &MusicPlayer::updateThumbnailToolBar);
}
					

會相應更新縮略圖工具欄按鈕,每當音樂迴放狀態改變時。

void MusicPlayer::updateThumbnailToolBar()
{
    playToolButton->setEnabled(mediaPlayer.duration() > 0);
    backwardToolButton->setEnabled(mediaPlayer.position() > 0);
    forwardToolButton->setEnabled(mediaPlayer.position() < mediaPlayer.duration());
    if (mediaPlayer.state() == QMediaPlayer::PlayingState) {
        playToolButton->setToolTip(tr("Pause"));
        playToolButton->setIcon(style()->standardIcon(QStyle::SP_MediaPause));
    } else {
        playToolButton->setToolTip(tr("Play"));
        playToolButton->setIcon(style()->standardIcon(QStyle::SP_MediaPlay));
    }
}
					

範例工程 @ code.qt.io