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);  //更改标题栏大小
}

四、运行测试

可以显示标题内容和图标

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

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

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

相关推荐
用户805533698031 天前
不止三件套:QObject 属性系统全关键字与运行时反射!
c++·qt
xcyxiner1 天前
DicomViewer (vcpkg Windows和ubuntu编译)7
qt
Quz6 天前
QML Hello World 入门示例
qt
xcyxiner9 天前
DicomViewer (dcmtk读取dcm文件)5
qt
xcyxiner10 天前
DicomViewer (后台线程处理文件)4
qt
xcyxiner10 天前
DicomViewer (添加模型类)3
qt
xcyxiner11 天前
DicomViewer (目录调整) 2
qt
xcyxiner11 天前
dcmtk vtk vtk-dicom(gdcm) 编译(debug) v2
qt
LDR00613 天前
Type-C 快充全面升级!LDR6601 赋能个人护理便携电机,重塑剃须刀 / 理发器新体验
c语言·开发语言
雪碧聊技术13 天前
Tree.js是什么?一文讲透
开发语言·javascript·ecmascript