Qt自定义标题栏

一、创建项目

最终项目文件结构如下

"iconfont.tff"的使用方式见如下博客,用于更改图标颜色
Qt更改图标颜色_怎么追摩羯座的博客-CSDN博客

二、MyTitleBar.pro

#-------------------------------------------------
#
# Project created by QtCreator 2023-08-28T09:46:06
#
#-------------------------------------------------

QT       += core gui

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

TARGET = MyTitleBar
TEMPLATE = app

# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS

# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

CONFIG += c++11

SOURCES += \
        main.cpp \
        mainwindow.cpp \
    titlebar.cpp

HEADERS += \
        mainwindow.h \
    titlebar.h

FORMS += \
        mainwindow.ui

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

RESOURCES += \
    file.qrc

二、创建自定义标题类TitleBar

titlebar.h代码如下

/**
 * @brief TitleBar 自定义标题栏
 */

#ifndef TITLEBAR_H
#define TITLEBAR_H

#include <QWidget>
class QLabel;
class QPushButton;

class TitleBar : public QWidget
{
    Q_OBJECT
public:
    explicit TitleBar(QWidget *parent = nullptr);
    ~TitleBar();

    void setColor(QString backgroundColor, QString fontColor, QString selectedFontColor);  //设置颜色
protected:

    //界面拖动
    void mousePressEvent(QMouseEvent* event);  //鼠标按下

    void mouseMoveEvent(QMouseEvent* event);  //鼠标移动

    void mouseReleaseEvent(QMouseEvent* event);  //鼠标抬起

    void mouseDoubleClickEvent(QMouseEvent* event);  //双击标题栏进行界面的最大化/还原

    bool eventFilter(QObject *obj, QEvent *event);  //事件过滤器

private slots:

    void onClicked();  //进行最小化、最大化/还原、关闭操作

    void updateMaximize();  //最大化/还原

private:
    QLabel* m_iconLabel;  //显示图标
    QLabel* m_titleLabel;  //显示标题
    QPushButton* m_minimizeButton;  //最小化按键
    QPushButton* m_maximizeButton;   //最大化/还原按键
    QPushButton* m_closeButton;   //关闭按键

    QPoint m_mousePosition;  //鼠标按下时的位置
    bool m_isMousePressed;  //鼠标是否摁下

    QString m_backgroundColor; //背景色
    QString m_fontColor; //字体色
    QString m_selectedFontColor; //被选中的字体色
};

#endif // TITLEBAR_H

titlebar.cpp代码如下

#include "titlebar.h"
#include <QLabel>
#include <QPushButton>
#include <QHBoxLayout>
#include <QEvent>
#include <QMouseEvent>
#include <QFontDatabase>
#include <QApplication>

TitleBar::TitleBar(QWidget *parent)
    : QWidget(parent)
{
    setFixedHeight(30);

    //控件初始化
    m_iconLabel = new QLabel(this);
    m_titleLabel = new QLabel(this);
    m_minimizeButton = new QPushButton(this);
    m_maximizeButton = new QPushButton(this);
    m_closeButton = new QPushButton(this);

    //图片自适应控件大小
    m_iconLabel->setFixedSize(20, 20);
    m_iconLabel->setScaledContents(true);

    //设置控件在布局(layout)里面的大小变化的属性
    m_titleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);

    //设置控件的最小大小和最大大小
    m_minimizeButton->setFixedSize(30, 25);
    m_maximizeButton->setFixedSize(30, 25);
    m_closeButton->setFixedSize(30, 25);

    //设置控件唯一标识符
    m_titleLabel->setObjectName("whiteLabel");
    m_minimizeButton->setObjectName("minimizeButton");
    m_maximizeButton->setObjectName("maximizeButton");
    m_closeButton->setObjectName("closeButton");

    //设置图标
    int fontId = QFontDatabase::addApplicationFont(":/font/iconfont.ttf");
    QString fontName = QFontDatabase::applicationFontFamilies(fontId).at(0);
    QFont iconFont = QFont(fontName);
    iconFont.setPixelSize(17);

    m_minimizeButton->setFont(iconFont);
    m_minimizeButton->setText(QChar(0xe61b));
    m_minimizeButton->setToolTip(tr("最小化"));
    m_minimizeButton->installEventFilter(this);

    m_maximizeButton->setFont(iconFont);
    m_maximizeButton->setText(QChar(0xe692));
    m_maximizeButton->setToolTip(tr("向下还原"));
    m_maximizeButton->installEventFilter(this);

    m_closeButton->setFont(iconFont);
    m_closeButton->setText(QChar(0xe723));
    m_closeButton->setToolTip(tr("关闭"));
    m_closeButton->installEventFilter(this);

    //控件布局
    QHBoxLayout *pLayout = new QHBoxLayout(this);
    pLayout->addWidget(m_iconLabel);
    pLayout->addSpacing(5);
    pLayout->addWidget(m_titleLabel);
    pLayout->addWidget(m_minimizeButton);
    pLayout->addWidget(m_maximizeButton);
    pLayout->addWidget(m_closeButton);
    pLayout->setSpacing(0);
    pLayout->setContentsMargins(5, 0, 5, 0);
    setLayout(pLayout);

    //信号槽绑定
    connect(m_minimizeButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
    connect(m_maximizeButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
    connect(m_closeButton, SIGNAL(clicked(bool)), this, SLOT(onClicked()));
}

TitleBar::~TitleBar()
{

}

/**
 * @brief MainWindow::mousePressEvent 鼠标双击:界面最大化或还原
 * @param event 鼠标事件
 */
void TitleBar::mouseDoubleClickEvent(QMouseEvent *event)
{
    Q_UNUSED(event);

    emit m_maximizeButton->clicked();
}

/**
 * @brief MainWindow::mousePressEvent 鼠标按下:准备移动
 * @param event 鼠标事件
 */
void TitleBar::mousePressEvent(QMouseEvent *event)
{
    m_mousePosition = event->pos();

    m_isMousePressed = true;
}

/**
 * @brief MainWindow::mousePressEvent 鼠标移动
 * @param event 鼠标事件
 */
void TitleBar::mouseMoveEvent(QMouseEvent *event)
{
    if (m_isMousePressed == true )
    {
        QWidget *pWindow = this->window();

        if(pWindow->isMaximized()) //界面最大时,先还原再移动
        {
            pWindow->showNormal();

            //防止鼠标指针在界面之外
            m_mousePosition = QPoint(200, 10);
            pWindow->move(event->globalPos().x() - 200, event->globalPos().y());
        }
        else
        {
            QPoint movePot = event->globalPos() - m_mousePosition;
            pWindow->move(movePot);
        }
    }
}

/**
 * @brief MainWindow::mousePressEvent 鼠标抬起:移动结束
 * @param event 鼠标事件
 */
void TitleBar::mouseReleaseEvent(QMouseEvent *event)
{
    Q_UNUSED(event);

    m_isMousePressed = false;
}

/**
 * @brief TitleBar::eventFilter 事件过滤器
 * @param obj 过滤对象
 * @param event 事件
 * @return
 */
bool TitleBar::eventFilter(QObject *obj, QEvent *event)
{
    switch(event->type())
    {
        case QEvent::WindowTitleChange:  //更改标题显示内容
            {
                QWidget *pWidget = qobject_cast<QWidget *>(obj);
                if(pWidget)
                {
                    m_titleLabel->setText(pWidget->windowTitle());
                }
            }
            break;
        case QEvent::WindowIconChange:  //更改图标
            {
                QWidget *pWidget = qobject_cast<QWidget *>(obj);
                if(pWidget)
                {
                    QIcon icon = pWidget->windowIcon();
                    m_iconLabel->setPixmap(icon.pixmap(m_iconLabel->size()));
                }
            }
            break;
        case QEvent::WindowStateChange:
        case QEvent::Resize:
                updateMaximize();  //最大化/还原
            break;
        case QEvent::Enter:  //鼠标悬停在控件上,控件变色
            {
                if(obj == m_minimizeButton)
                {
                    m_minimizeButton->setStyleSheet(QString("QPushButton{background-color:rgba(0,0,0,0);color:%1}").arg(m_selectedFontColor));
                }
                else if(obj == m_closeButton)
                {
                    m_closeButton->setStyleSheet(QString("QPushButton{background-color:rgba(0,0,0,0);color:%1}").arg(m_selectedFontColor));
                }
                else if(obj == m_maximizeButton)
                {
                    m_maximizeButton->setStyleSheet(QString("QPushButton{background-color:rgba(0,0,0,0);color:%1}").arg(m_selectedFontColor));
                }
            }
            break;
        case QEvent::Leave:  //鼠标离开控件,颜色恢复
            {
                if(obj == m_minimizeButton)
                {
                    m_minimizeButton->setStyleSheet(QString("QPushButton{background-color:rgba(0,0,0,0);color:%1}").arg(m_fontColor));
                }
                else if(obj == m_closeButton)
                {
                    m_closeButton->setStyleSheet(QString("QPushButton{background-color:rgba(0,0,0,0);color:%1}").arg(m_fontColor));
                }
                else if(obj == m_maximizeButton)
                {
                    m_maximizeButton->setStyleSheet(QString("QPushButton{background-color:rgba(0,0,0,0);color:%1}").arg(m_fontColor));
                }
            }
            break;
        default:
        break;
    }

    return QWidget::eventFilter(obj, event);
}

/**
 * @brief TitleBar::onClicked 进行最小化、最大化/还原、关闭操作
 */
void TitleBar::onClicked()
{
    QPushButton *pButton = qobject_cast<QPushButton *>(sender());
    QWidget *pWindow = this->window();
    if (pWindow->isTopLevel())
    {
        if(pButton == m_minimizeButton)  //最小化
        {
            pWindow->showMinimized();
        }
        else if (pButton == m_maximizeButton)  //最大化、还原
        {
            pWindow->isMaximized() ? pWindow->showNormal() : pWindow->showMaximized();
        }
        else if (pButton == m_closeButton)  //关闭
        {
            pWindow->close();
        }
    }
}

/**
 * @brief TitleBar::updateMaximize 最大化/还原时,更改图标样式
 */
void TitleBar::updateMaximize()
{
    QWidget *pWindow = this->window();
    if(pWindow->isTopLevel())
    {
        bool bMaximize = pWindow->isMaximized();
        if(bMaximize)
        {
            m_maximizeButton->setToolTip(tr("向下还原"));
            m_maximizeButton->setProperty("maximizeProperty", "向下还原");
            m_maximizeButton->setText(QChar(0xe692));
        }
        else
        {
            m_maximizeButton->setProperty("maximizeProperty", "最大化");
            m_maximizeButton->setToolTip(tr("最大化"));
            m_maximizeButton->setText(QChar(0xe65d));
        }

        m_maximizeButton->setStyle(QApplication::style());
    }
}

/**
 * @brief TitleBar::setColor 更改颜色
 * @param backgroundColor  背景色
 * @param fontColor 控件颜色/字体颜色
 * @param selectedFontColor 鼠标悬停在控件上时的颜色
 */
void TitleBar::setColor(QString backgroundColor, QString fontColor, QString selectedFontColor)
{
    m_backgroundColor = backgroundColor;
    m_fontColor = fontColor;
    m_selectedFontColor = selectedFontColor;

    //按键背景透明,图标颜色为m_fontColor
    m_minimizeButton->setStyleSheet(QString("QPushButton{background-color:rgba(0,0,0,0);color:%1}").arg(m_fontColor));
    m_maximizeButton->setStyleSheet(QString("QPushButton{background-color:rgba(0,0,0,0);color:%1}").arg(m_fontColor));
    m_closeButton->setStyleSheet(QString("QPushButton{background-color:rgba(0,0,0,0);color:%1}").arg(m_fontColor));

    m_titleLabel->setStyleSheet(QString("QLabel{color:%1}").arg(m_fontColor));
}

三、使用

mainwindow.h代码如下

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include "titlebar.h"

namespace Ui {
class MainWindow;
}

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    explicit MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

protected:
    void resizeEvent(QResizeEvent *event);

private:
    Ui::MainWindow *ui;

    TitleBar* m_titleBar;  //自定义标题栏
};

#endif // MAINWINDOW_H

mainwindow.cpp代码如下

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent) :
    QMainWindow(parent),
    ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    m_titleBar = new TitleBar(this);
    m_titleBar->resize(this->width(), 30);
    m_titleBar->move(0, 0);
    installEventFilter(m_titleBar);
    setWindowTitle("Custom Window");  //设置标题内容
    setWindowIcon(QIcon(":/font/capricorn.png"));  //设置图标

    //第一个是去掉原边框及标题栏,第二个是保留最小化及还原功能,主要是为了还原,最小化下面实现了
    this->setWindowFlags(Qt::FramelessWindowHint | Qt::WindowMinimizeButtonHint);
    ui->menuBar->setVisible(false);  //隐藏菜单栏
    ui->mainToolBar->setVisible(false);  //隐藏工具栏
    //ui->statusBar->setVisible(false);  //隐藏状态栏
    this->showMaximized();  //最大化显示

    QString backgroundColor = "black"; //背景色
    QString fontColor = "white"; //字体色
    QString selectedFontColor = "red"; //被选中的字体色

    //渐变背景
    this->setStyleSheet(QString("QMainWindow#MainWindow{background-color:qlineargradient(x1:0, y1:0, x2:1, y2:1, stop:0 %1, stop:1 %2);}")
                        .arg(backgroundColor).arg(fontColor));

    //设置标题栏颜色
    m_titleBar->setColor(backgroundColor, fontColor, selectedFontColor);
}

MainWindow::~MainWindow()
{
    delete ui;
}

/**
 * @brief MainWindow::resizeEvent  当界面大小改变时更改标题栏大小
 * @param event
 */
void MainWindow::resizeEvent(QResizeEvent *event)
{
    Q_UNUSED(event);

    m_titleBar->resize(this->width(), 30);  //更改标题栏大小
}

四、运行测试

可以显示标题内容和图标

双击标题栏,可以放大缩小,放大/还原图标样式会更改

左键按下标题栏,可以移动界面;当最大化时,界面会先还原再移动

鼠标停放在按键上,按键会变颜色

相关推荐
秋夜白2 分钟前
【排序算法 python实现】
开发语言·python·排序算法
Legendary_00819 分钟前
LDR6020驱动的Type-C接口显示器解决方案
c语言·开发语言·计算机外设
techdashen24 分钟前
Go context.Context
开发语言·后端·golang
凡人的AI工具箱26 分钟前
40分钟学 Go 语言高并发:Select多路复用
开发语言·后端·架构·golang
ModelBulider31 分钟前
SpringMVC应用专栏介绍
java·开发语言·后端·spring·springmvc
恬淡虚无真气从之33 分钟前
go 结构体方法
开发语言·后端·golang
licy__34 分钟前
Python BeautifulSoup 常用语句详解
开发语言·python·beautifulsoup
努力的Java程序员35 分钟前
后端接受大写参数(亲测能用)
java·开发语言
一雨方知深秋39 分钟前
WEB APIS(DOM对象,操作元素内容,属性,表单属性,自定义属性,定时器)
开发语言·前端·javascript
EasyNTS40 分钟前
视频流媒体播放器EasyPlayer.js网页直播/点播播放器:如何清除浏览器缓存
开发语言·javascript·缓存