音乐播放器

Screenshot of the Music Player example

音乐播放器范例演示如何使用各种提供特征通过 QtWinExtras 模块。

注意: The example uses QMediaPlayer QtMultimedia module to play the music, but this article focuses on the parts where QtWinExtras 特征的使用。

DWM 特征

范例使用 Windows DWM (桌面窗口管理器) 特征以将窗口内容视觉集成到窗口框架,并使主窗口、音量弹出窗口半透明和模糊。

范例基于是否启用合成,应用不同外观。当合成被启用时,主窗口变半透明且窗口框架会扩展到客户端区域,以使窗口内容无缝集成到窗口框架,如上所示。当合成被禁用时,将着色颜色用作背景颜色。以下屏幕截图阐明 Music Player 范例外观如何当合成被禁用时。

Screenshot of the Music Player example

各自代码组合扩展或重置系统框架,调节必要 QWidget 属性,并设置适当样式表以达成期望外观。

void MusicPlayer::stylize()
{
    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 (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()));
    }
}
					

The example application respects the user's composition settings, reacts to dynamic composition changes, and looks solid regardless of whether composition is enabled or not. It accomplishes this by catching QWinEvent::CompositionChange and QWinEvent::ColorizationChange events and adjusting its looks accordingly.

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("."),
                      QLatin1Char('"') + QDir::toNativeSeparators(filePath) + QStringLiteral("\" \"%1\""));
    return true;
}
					

任务栏叠加和进度

范例使用 Windows 任务栏为 2 件事;设置表示当前音乐回放状态的叠加图标,和在任务栏按钮指示回放进度。

Screenshot of the Music Player taskbar

The following snippet shows how the taskbar button is prepared. The playback progress is wired directly to the taskbar progress indicator by using signals and slots.

void MusicPlayer::createTaskbar()
{
    taskbarButton = new QWinTaskbarButton(this);
    taskbarButton->setWindow(windowHandle());
    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);
    thumbnailToolBar->setWindow(windowHandle());
    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));
    }
}
					

文件: