【QT学习】自定义标题栏

内容:

实现标题栏的自定义以及窗口缩放事件的重写。

自定义了一个标题栏类CommonTitleBar

.h文件

c++ 复制代码
#pragma once
#include <qwidget.h>
#include <qpushbutton.h>
#include <qlabel.h>
#include <QHBoxLayout>
#include <QEvent>
#include <QMouseEvent>
#include <QApplication>
#include <qframe.h>
#include <qdebug.h>
#include <qfile.h>
class CommonTitleBar :
    public QWidget
{
    Q_OBJECT
public:
    explicit CommonTitleBar(QWidget* parent = nullptr);
    void setTitleText(QString titleText);
    
private:
    QPushButton* _closeButton; //关闭按键
    QPushButton* _lockButton; //锁定按键
    QFrame* _partingLine; //分割线
    QLabel* _titleLabel; //显示标题

private slots:
    void slotCloseClicked(); //关闭按钮
    void slotLockClicked(); // 锁定按钮
};

.cpp文件

cpp 复制代码
#include "CommonTitleBar.h"
CommonTitleBar::CommonTitleBar(QWidget* parent) : QWidget(parent)
{
    //标题栏固定高度
    this->setFixedHeight(24);
    // 控件初始化
    _titleLabel = new QLabel(this);
    _closeButton = new QPushButton(this);
    _lockButton = new QPushButton(this);
    _partingLine = new QFrame(this);

    // label相关设置
    _titleLabel->setFixedHeight(23); // 固定高度
    // 让label在水平方向上扩展(充当弹簧,不用弹簧是因为弹簧没办法设置背景颜色)
    _titleLabel->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
    // 文字 水平居左 垂直居中
    _titleLabel->setAlignment(Qt::AlignLeft| Qt::AlignVCenter);
    // 字体大小 样式 加粗
    _titleLabel->setObjectName("CommonTitleBar_titleLabel");

    // 按钮相关设置
    // 设置关闭按钮 大小 图标 提示词 无边框
    _closeButton->setFixedSize(23, 23);
    _closeButton->setIcon(QIcon(":/icon/close.png"));
    _closeButton->setToolTip("关闭");
    // 设置名字 用于QSS样式表
    _closeButton->setObjectName("CommonTitleBar_closeButton");
    // 设置钉按钮 大小 图标 提示词 无边框
    _lockButton->setFixedSize(23, 23);
    _lockButton->setIcon(QIcon(":/icon/lock.png"));
    _lockButton->setToolTip("钉在桌面");
    _lockButton->setObjectName("CommonTitleBar_lockButton");
    // 分割线相关设置 
    // 高度固定为1   设为水平 
    _partingLine->setFixedHeight(1);
    _partingLine->setFrameShape(QFrame::HLine);
    // 分割线的颜色  rgb(36,36,38)
    _partingLine->setObjectName("CommonTitleBar_partingLine");
    // 控件布局 
    // 水平布局
    QHBoxLayout* horizontalLayout = new QHBoxLayout;
    horizontalLayout->setSpacing(0); //布局中控件之间的间隔(间隙)
    horizontalLayout->setContentsMargins(0, 0, 0, 0); //清除布局边距,即布局与其父容器边缘之间的空间
    horizontalLayout->addWidget(_titleLabel);
    horizontalLayout->addWidget(_lockButton);
    horizontalLayout->addWidget(_closeButton);
    // 垂直布局
    QVBoxLayout* verticalLayout = new QVBoxLayout;
    verticalLayout->setContentsMargins(0, 0, 0, 0); //清除布局边距
    verticalLayout->addLayout(horizontalLayout);
    verticalLayout->addWidget(_partingLine);
    this->setLayout(verticalLayout);
    //信号槽绑定
    connect(_closeButton, &QPushButton::clicked, this, &CommonTitleBar::slotCloseClicked);
    connect(_lockButton, &QPushButton::clicked, this, &CommonTitleBar::slotLockClicked);
}

// 设置标题显示内容
void CommonTitleBar::setTitleText(QString titleText)
{
    _titleLabel->setText(titleText);
}

// 关闭按钮
void CommonTitleBar::slotCloseClicked()
{
    this->window()->close();
}
// 锁定按钮
void CommonTitleBar::slotLockClicked()
{
    // 切换btnClose的锁定状态
    bool isLocked = _closeButton->isEnabled();

    _closeButton->setEnabled(!isLocked);

    if (isLocked) {
        _lockButton->setIcon(QIcon(":/icon/lockRed.png"));
    }
    else {
        _lockButton->setIcon(QIcon(":/icon/lock.png"));
    }
}

主界面里面实例化这个标题栏,同时将主界面的标题栏去掉

(注意,去掉之后窗口的缩放也就没有了,需要重写事件)

所以我们要在主界面中重写标题栏的一系列事件(关闭、移动)以及窗口的缩放事件。

.h文件

cpp 复制代码
#pragma once

#include <QtWidgets/QWidget>
#include "ui_LiveStreamMasterControl.h"
#include "CommonTitleBar.h"
#include "ServerListDisplay.h"
#include "ServerSync.h"
#include "ServerManagement.h"
#include "serverinfo.h"
#include <QList>
#include <QMap>
#include "networkmanager.h"
class LiveStreamMasterControl : public QWidget
{
    enum class EdgeBlockMark
    {
        EdgeBlockMarkInit = 0,
        EdgeBlockMarkRightDown,
        EdgeBlockMarkLeftDown
    };
    
    Q_OBJECT

public:
    LiveStreamMasterControl(QWidget *parent = nullptr);
    ~LiveStreamMasterControl();
    void loadStyleSheet(); //初始化控件样式

    //槽函数
    // 刷新服务器选择列表
    void soltServerSelectListRefresh();
    void soltUpdateProjectInfoForm();
    void ConstructUeData(ServerInfo& serverinfo, QString index);
private:
    Ui::LiveStreamMasterControlClass ui;
    // 自定义标题栏
    CommonTitleBar* _titleBar;
    // 关于鼠标事件
    EdgeBlockMark  _edgeMark = EdgeBlockMark::EdgeBlockMarkInit;// 边缘标记
    bool _isMousePressedEdge = false; // 鼠标是否在边界范围内被按下
    QPoint _mousePosition; //鼠标按下时的位置
    bool _isMousePressedTitle = false; //鼠标是否在标题栏中被按下
protected:
    void mousePressEvent(QMouseEvent* event); //鼠标按下
    void mouseMoveEvent(QMouseEvent* event); //鼠标移动
    void mouseReleaseEvent(QMouseEvent* event); //鼠标抬起
    // void resizeEvent(QResizeEvent*);//窗口重置大小

};

.cpp文件

cpp 复制代码
#include "LiveStreamMasterControl.h"

LiveStreamMasterControl::LiveStreamMasterControl(QWidget *parent)
    : QWidget(parent)
{
    ui.setupUi(this);
    // 开启鼠标跟踪  这个要开启 否则无法获得鼠标坐标
    this->setMouseTracking(true);
    //this->setStyleSheet("background-color: rgb(51,51,55); color: white;font-family: Microsoft YaHei; ");
    loadStyleSheet();// 加载qss样式
    // 去掉原边框及标题栏
    this->setWindowFlags(Qt::FramelessWindowHint);
    // 设置窗口大小
    this->setMinimumSize(QSize(913, 589));
	// 自定义标题栏
    _titleBar = new CommonTitleBar(this);
    _titleBar->setTitleText("  LiveStream");
	
	// 创建一个空窗口  然后使用一个布局把空窗口和标题栏添加进去
	// .....

	

}
// 鼠标按下事件
void LiveStreamMasterControl::mousePressEvent(QMouseEvent* event)
{
    int edgeSize = 10; //设置边缘范围

    if (event->button() == Qt::LeftButton) // 左键被按下
    {
        //判断鼠标点击坐标是否在标题栏中
        if (_titleBar->pos().x() <= event->pos().x() && _titleBar->pos().y() <= event->pos().y()
            && (_titleBar->pos().x() + _titleBar->width()) >= event->pos().x()
            && (_titleBar->pos().y() + _titleBar->height()) >= event->pos().y())
        {
            _mousePosition= event->pos();// 记录下鼠标的按下位置
            _isMousePressedTitle = true; // 鼠标在标题栏中被按下状态置为true
        }
        else if ((this->width() - edgeSize < event->pos().x()) && (event->pos().x() < this->width())
            && (this->height() - edgeSize < event->pos().y()) && (event->pos().y() < this->height()))// 右下角
        {
            _isMousePressedEdge = true;// 鼠标在边界范围中被按下状态置为true
            _edgeMark = EdgeBlockMark::EdgeBlockMarkRightDown;// 边缘标记为 右下角
        }
        else if ((0 < event->pos().x()) && (event->pos().x() < edgeSize)
            && (this->height() - edgeSize < event->pos().y()) && (event->pos().y() < this->height()))  //左下角
        {
            _isMousePressedEdge = true;// 鼠标在边界范围中被按下状态置为true
            _edgeMark = EdgeBlockMark::EdgeBlockMarkLeftDown; // 边缘标记为 左下角
        }
    }
}

// 鼠标移动事件
void LiveStreamMasterControl::mouseMoveEvent(QMouseEvent* event)
{
    int edgeSize = 10; //设置边缘范围
    
    // 鼠标在标题栏中被按下的情况
    if ((event->buttons() & Qt::LeftButton) &&  _isMousePressedTitle == true)
    {
        // 计算鼠标从按下时的位置(m_mousePosition)到当前位置(event->globalPos())的偏移量
        // 将窗口的位置移动到新的位置
        move(event->globalPos() - _mousePosition);
    }
    else if ((event->buttons() & Qt::LeftButton) && _isMousePressedEdge == true)// 鼠标在左/右下角中被按下的情况
    {
        if(_edgeMark == EdgeBlockMark::EdgeBlockMarkRightDown)
        {
            QRect rect = this->geometry(); //存储当前窗口部件的几何尺寸和位置
            rect.setBottom(this->mapToParent(event->pos()).y()); // 设置底部
            rect.setRight(this->mapToParent(event->pos()).x()); // 设置右侧
            this->setGeometry(rect); // 重新设置窗口的大小和尺寸
        }
        else if (_edgeMark == EdgeBlockMark::EdgeBlockMark::EdgeBlockMarkLeftDown)
        {
            QRect rect = this->geometry(); //存储当前窗口部件的几何尺寸和位置
            rect.setBottom(this->mapToParent(event->pos()).y()); // 设置底部
            rect.setLeft(this->mapToParent(event->pos()).x()); // 设置左侧
            this->setGeometry(rect); // 重新设置窗口的大小和尺寸
        }
    }
    else if ( (this->width() - edgeSize < event->pos().x()) && (event->pos().x() < this->width())
        && (this->height() - edgeSize < event->pos().y()) && (event->pos().y() < this->height()))  //右下角
    {
        this->setCursor(Qt::SizeFDiagCursor);// 设置光标变化
    }
    else if ((0 < event->pos().x()) && (event->pos().x() < edgeSize)
        && (this->height() - edgeSize < event->pos().y()) && (event->pos().y() < this->height()))  //左下角
    {
        this->setCursor(Qt::SizeBDiagCursor);// 设置光标变化
    }
    else if ((0 < event->pos().y()) && (event->pos().y() < this->height() - edgeSize))  // 中间部分
    {
        this->setCursor(Qt::ArrowCursor);// 恢复光标
    }
    else if ((this->height() - edgeSize < event->pos().y()) && (event->pos().y() < this->height())
        && (edgeSize < event->pos().x()) && (event->pos().x() < this->width() - edgeSize)) // 中间底部
    {
        this->setCursor(Qt::ArrowCursor);// 恢复光标
    }
}
// 鼠标释放事件
void LiveStreamMasterControl::mouseReleaseEvent(QMouseEvent* event)
{
    Q_UNUSED(event);
    _isMousePressedEdge = false;// 鼠标在边缘范围内按下状态置为false
    _isMousePressedTitle = false;// 鼠标在标题栏内被按下状态置为false
    _edgeMark = EdgeBlockMark::EdgeBlockMarkInit; // 边缘标记 初始化
}
相关推荐
OpenC++3 分钟前
【C++QT】Buttons 按钮控件详解
c++·经验分享·qt·leetcode·microsoft
LucianaiB27 分钟前
【金仓数据库征文】_AI 赋能数据库运维:金仓KES的智能化未来
运维·数据库·人工智能·金仓数据库 2025 征文·数据库平替用金仓
2501_9153738840 分钟前
Node.js 学习入门指南
学习·node.js
时序数据说1 小时前
时序数据库IoTDB在航空航天领域的解决方案
大数据·数据库·时序数据库·iotdb
我真的不会C1 小时前
QT窗口相关控件及其属性
开发语言·qt
.生产的驴1 小时前
SpringBoot 封装统一API返回格式对象 标准化开发 请求封装 统一格式处理
java·数据库·spring boot·后端·spring·eclipse·maven
绵绵细雨中的乡音1 小时前
Linux进程学习【基本认知】
linux·运维·学习
AnsenZhu1 小时前
2025年Redis分片存储性能优化指南
数据库·redis·性能优化·分片
oydcm1 小时前
MySQL数据库概述
数据库·mysql
oioihoii2 小时前
C++23中if consteval / if not consteval (P1938R3) 详解
java·数据库·c++23