Qt在win10自定义标题栏,应用主题颜色到标题栏

Qt自定义标题栏
本文介绍如何在Qt中为应用程序自定义标题栏,并应用Windows 10的主题颜色。通过使用QtWin API,实现标题栏颜色跟随系统主题变化,并提供最小化、最大化/还原及关闭按钮的功能。

前言

Qt自定义标题栏的资料很多了,但是百度来github去,没找到应用win10的主题颜色到标题栏,就自己折腾了一下。弄了个Demo。没什么技术含量,献丑了。

先看效果

顺手绘制了按钮
在这里插入图片描述
在这里插入图片描述

设置应用颜色到标题栏

截图中实现了标题栏颜色和拖动改变窗口位置。

关键点

QtWin

在.pro文件中加入

QT   += winextras

就可以使用QtWin命名空间中的API。这里我们使用

QColor QtWin::realColorizationColor()

根据文档描述:
在这里插入图片描述
这玩意儿返回的是带有Alpha的标题栏颜色。OK这样就是真实的颜色了。另外一个函数:

QColor QtWin::colorizationColor(bool *opaqueBlend = Q_NULLPTR)

返回的颜色有色差。

注册表获取是否应用了颜色到标题栏

这个东西好像不是公开的,经过我一番折腾,发现了在注册表的这个位置:

HKEY_CURRENT_USER\\Software\\Microsoft\\Windows\\DWM

的这个key对应了上面我们开启的“应用颜色到标题栏和窗口边框”
在这里插入图片描述
有了这两个东西就好办了,就算是热更改,只需要在需要显示颜色的窗口的绘制事件中绘制上这个颜色就搞定了。

代码

头文件:captionwidget.h

// captionwidget.h
#ifndef CAPTIONWIDGET_H
#define CAPTIONWIDGET_H

#include <QWidget>

#ifdef Q_OS_WIN
class CaptionWidget : public QWidget
{
   
   
    Q_OBJECT
public:
    explicit CaptionWidget(QWidget *parent = 0);

    bool event(QEvent *e) override;
signals:
    void btnMinClicked();
    void btnMaxNormalClicked();
    void btnCloseClicked();
    void DwmCompsitionChanged();

protected:
    // QWidget interface
    bool nativeEvent(const QByteArray &eventType, void *message, long *result) override;
    void paintEvent(QPaintEvent *event) override;
    void mouseMoveEvent(QMouseEvent *event) override;
    void mousePressEvent(QMouseEvent *event) override;
    void mouseReleaseEvent(QMouseEvent *event) override;
    void mouseDoubleClickEvent(QMouseEvent *event) override;
    void leaveEvent(QEvent *event) override;

private:
    enum RectType{
   
   
        Rect_Other = -1,
        Rect_Mini,
        Rect_NormalMax,
        Rect_Close,
    };

    enum IconType{
   
   
        Icon_Mini,
        Icon_Max,
        Icon_Restore,
        Icon_Close,
    };

    bool mini_hover_;
    bool max_hover_;
    bool close_hover_;

    void setTopLevelWidget();

    QRectF getRect(RectType type);
    QPixmap getPixmap(IconType type,const QColor &color);
    QColor getIconColor(bool isClose = false);
    int itemAt(const QPoint &pos);

    static QColor getForgroundColor(const QColor &backgroundColor);

    /// \brief windows8以上版本,获取是否将主题颜色应用到标题栏和边框
    /// \return
    ///
    static bool dwmColorPrevalence();
};
#else
class CaptionWidget : public QWidget
{
   
   
    Q_OBJECT
public:
    CaptionWidget(QWidget *parent = nullptr, Qt::WindowFlags f = Qt::WindowFlags())
        : QWidget(parent, f)
    {
   
   
    }
};
#endif // Q_OS_WIN

#endif // CAPTIONWIDGET_H

源文件:captionwidget.cpp

// captionwidget.cpp
#include "captionwidget.h"
#include <QSettings>
#include <QtGlobal>

#ifdef Q_OS_WIN
#include <QPaintEvent>
#include <QMouseEvent>
#include <QHelpEvent>
#include <QPainter>
#include <QtDebug>
#include <QToolTip>
#include <QtWin>
#include <QToolTip>
#include <QStyle>

#include <Windows.h>
#pragma comment(lib, "User32.lib")

CaptionWidget::CaptionWidget(QWidget *parent)
    : QWidget(parent)
    , mini_hover_(false)
    , max_hover_(false)
    , close_hover_(false)
{
   
   
    setMouseTracking(true);

    setTopLevelWidget();
}

void CaptionWidget::setTopLevelWidget()
{
   
   
    auto w = this->window();
    connect(this, &CaptionWidget::btnMinClicked, w, &QWidget::showMinimized);
    connect(this, &CaptionWidget::btnMaxNormalClicked, w, [=](){
   
   
        auto state = w->windowState();
        if(state.testFlag(Qt::WindowMaximized)){
   
   
            w->showNormal();
        }else if(state.testFlag(Qt::WindowNoState)){
   
   
            w->showMaximized();
        }

    });
    connect(this, &CaptionWidget::btnCloseClicked, w, &QWidget::close);
}

/// QWidget在鼠标移动后停留的短暂时间内,会触发一次QEvent::ToolTip
/// 如果自绘制的按钮,可以在event中显示tooltip
bool CaptionWidget::event(QEvent *e)
{
   
   
    if (e->type() == QEvent::ToolTip) {
   
   
        QHelpEvent *helpEvent = static_cast<QHelpEvent *>(e);
        int index = itemAt(helpEvent->pos());
        if (index != -1) {
   
   
            QString str;
            switch (index) {
   
   
            case Rect_Mini:
                str = tr("minimize");
                break;
            case Rect_NormalMax:

                str = this->window()-
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值