Qt高级--(2)自定义标题栏

news2024/10/6 16:20:19

自定义标题栏

功能点

1.标题栏中最外层布局器使用水平布局器。
2.导航按钮、工具按钮和窗口功能按钮都是用水平布局器,边距和间隔可根据实际情况设置。
3.编写 QSS 样式,并将样式设置到窗口控件中。
4.实现最小化、最大化和关闭窗口按钮功能。
5.实现鼠标双击标题栏切换窗口状态,最大化状态时切换至正常状态,正常状态切换至最大化状态。
6.鼠标拖动标题栏可在屏幕中移动窗口。
7.鼠标拖动窗体切换窗口状态,拖动至屏幕顶部切换至最大化状态,拖动离开屏幕顶部切换至正常状态。

在这里插入图片描述

源代码

JTitleBar .h

#ifndef JTITLEBAR_H
#define JTITLEBAR_H

#include <QWidget>
#include <QMouseEvent>
#include "jnavibutton.h"

namespace Ui {
class JTitleBar;
}

class JTitleBar : public QWidget
{
    Q_OBJECT

public:
    explicit JTitleBar(QWidget *parent = 0);
    ~JTitleBar();

    enum WINSTATUS {NORMAL, MAXIMIZED, MINIMIZED};
    Q_ENUMS(WINSTATUS)

    void setTitleHeight(int height);

public Q_SLOTS:
    virtual void mousePressEvent(QMouseEvent *event) override;
    virtual void mouseReleaseEvent(QMouseEvent *event) override;
    virtual void mouseMoveEvent(QMouseEvent *event) override;
    virtual void mouseDoubleClickEvent(QMouseEvent *event) override;

Q_SIGNALS:
    void nbtnTab1_clicked();
    void nbtnTab2_clicked();
    void nbtnTab3_clicked();
    void configWin_clicked();
    void changeSkin_clicked();

private:
    void winStatus_changed();

private:
    Ui::JTitleBar *ui;

private:
    QList<JNaviButton*> m_listNaviButtons;
    QList<QPushButton*> m_listToolButtons;
    QList<QPushButton*> m_listWinButtons;
    int m_titleHeight;
    QPoint m_startPos;
    bool m_bLeftButtonPressed;
    WINSTATUS m_winStatus;
    bool m_bDragMax;
};

#endif // JTITLEBAR_H

.cpp

#include "jtitlebar.h"
#include "ui_jtitlebar.h"
#include <QHBoxLayout>

JTitleBar::JTitleBar(QWidget *parent) :
    QWidget(parent),
    ui(new Ui::JTitleBar),
    m_titleHeight(30),
    m_bLeftButtonPressed(false),
    m_winStatus(NORMAL),
    m_bDragMax(false)
{
    ui->setupUi(this);
    
    QHBoxLayout *ui_hLayNaviButton = new QHBoxLayout;
    ui_hLayNaviButton->addWidget(ui->nbtnTab1);
    ui_hLayNaviButton->addWidget(ui->nbtnTab2);
    ui_hLayNaviButton->addWidget(ui->nbtnTab3);
    ui_hLayNaviButton->addStretch();
    ui_hLayNaviButton->setContentsMargins(QMargins(0,0,0,0));
    ui_hLayNaviButton->setSpacing(0);
    ui->nbtnTab1->setChecked(true);
    ui->nbtnTab1->setText(QStringLiteral("Tab1"));
    ui->nbtnTab2->setText(QStringLiteral("Tab2"));
    ui->nbtnTab3->setText(QStringLiteral("Tab3"));
    connect(ui->nbtnTab1, &JNaviButton::clicked, [=](){ emit nbtnTab1_clicked(); });
    connect(ui->nbtnTab2, &JNaviButton::clicked, [=](){ emit nbtnTab2_clicked(); });
    connect(ui->nbtnTab3, &JNaviButton::clicked, [=](){ emit nbtnTab3_clicked(); });
    m_listNaviButtons << ui->nbtnTab1 << ui->nbtnTab2 << ui->nbtnTab3;
    ui->nbtnTab1->setNormalIcon(QPixmap(":/icon/icon/tab1.png"));
    ui->nbtnTab1->setHoverIcon(QPixmap(":/icon/icon/tab1-hover.png"));
    ui->nbtnTab1->setCheckedIcon(QPixmap(":/icon/icon/tab1-hover.png"));
    ui->nbtnTab2->setNormalIcon(QPixmap(":/icon/icon/tab2.png"));
    ui->nbtnTab2->setHoverIcon(QPixmap(":/icon/icon/tab2-hover.png"));
    ui->nbtnTab2->setCheckedIcon(QPixmap(":/icon/icon/tab2-hover.png"));
    ui->nbtnTab3->setNormalIcon(QPixmap(":/icon/icon/tab3.png"));
    ui->nbtnTab3->setHoverIcon(QPixmap(":/icon/icon/tab3-hover.png"));
    ui->nbtnTab3->setCheckedIcon(QPixmap(":/icon/icon/tab3-hover.png"));
    for(auto btn : m_listNaviButtons) {
        btn->setShowIcon(true);// 设置导航按钮显示图标
        btn->setNormalBgColor(QColor(50, 57, 76, 0));
        btn->setHoverBgColor(QColor(0, 0, 0, 50));
        btn->setCheckedBgColor(QColor(0, 0, 0, 100));
        btn->setNormalTextColor(QColor(210, 210, 215));
        btn->setHoverTextColor(QColor(255, 255, 255));
        btn->setCheckedTextColor(QColor(255, 255, 255));
        btn->setIconSpace(20);// 设置图标左侧边距
        btn->setPaddingLeft(30);// 设置文字左侧边距
    }

    QHBoxLayout *ui_hlayToolButton = new QHBoxLayout;
    ui_hlayToolButton->addWidget(ui->btnProject);
    ui_hlayToolButton->addWidget(ui->btnEdit);
    ui_hlayToolButton->addWidget(ui->btnSetting);
    ui_hlayToolButton->addWidget(ui->btnAbout);
    QMargins margin = ui_hlayToolButton->contentsMargins();
    margin.setRight(margin.right() + 10);
    ui_hlayToolButton->setContentsMargins(margin);
    m_listToolButtons << ui->btnProject << ui->btnEdit << ui->btnSetting << ui->btnAbout;

    QHBoxLayout *ui_hlayWinButton = new QHBoxLayout;
    ui_hlayWinButton->addWidget(ui->btnSkin);
    ui_hlayWinButton->addWidget(ui->btnMin);
    ui_hlayWinButton->addWidget(ui->btnMax);
    ui_hlayWinButton->addWidget(ui->btnClose);
    ui_hlayWinButton->setSpacing(0);
    margin = ui_hlayWinButton->contentsMargins();
    margin.setLeft(margin.left() + 10);
    margin.setRight(margin.right() + 10);
    ui_hlayWinButton->setContentsMargins(margin);
    connect(ui->btnSetting, &QPushButton::clicked, [=](){ emit configWin_clicked(); });
    connect(ui->btnSkin, &QPushButton::clicked, [=](){ emit changeSkin_clicked(); });
    connect(ui->btnMin, &QPushButton::clicked, this, [=](){ parentWidget()->showMinimized(); });
    connect(ui->btnMax, &QPushButton::clicked, [=](){ winStatus_changed(); });
    connect(ui->btnClose, &QPushButton::clicked, [=](){ parentWidget()->close(); });
    m_listWinButtons << ui->btnSkin << ui->btnMin << ui->btnMax << ui->btnClose;





   
    QHBoxLayout *ui_hlayWindow = new QHBoxLayout;
    ui_hlayWindow->addWidget(ui->btnLogo);		// 添加 LOGO 按钮
    ui_hlayWindow->addLayout(ui_hLayNaviButton);// 添加导航按钮所在布局器
    ui_hlayWindow->addStretch();				// 添加一个弹簧
    ui_hlayWindow->addLayout(ui_hlayToolButton);// 添加工具按钮所在布局器
    ui_hlayWindow->addWidget(ui->frameLine);	// 添加竖线
    ui_hlayWindow->addLayout(ui_hlayWinButton);// 添加窗口功能按钮所在布局器
    ui->btnLogo->setMinimumWidth(180);			// 为 LOGO 按钮设置最小宽度
    ui->frameLine->setFixedSize(1, 20);			// 将竖线的尺寸设为固定值
    ui_hlayWindow->setContentsMargins(QMargins(0,0,0,0));
    ui_hlayWindow->setSpacing(0);


    setLayout(ui_hlayWindow);
    setAttribute(Qt::WA_StyledBackground, true);

/*
    QString style = "QWidget#JTitleBar{background: qlineargradient(x1:0,y1:0,x2:1,y2:0,stop:0 #313947,stop:1 #34375E);}"
                    "QPushButton{border: none;}"
                    "QPushButton#btnLogo{color:white;}"
                    "QPushButton#btnProject{image: url(:/icon/icon/project.png); color:white;}"
                    "QPushButton#btnProject:hover{image: url(:/icon/icon/project-hover.png);}"
                    "QPushButton#btnEdit{image: url(:/icon/icon/analysis.png); color:white;}"
                    "QPushButton#btnEdit:hover{image: url(:/icon/icon/analysis-hover.png);}"
                    "QPushButton#btnSetting{image: url(:/icon/icon/setting.png); color:white;}"
                    "QPushButton#btnSetting:hover{image: url(:/icon/icon/setting-hover.png);}"
                    "QPushButton#btnAbout{image: url(:/icon/icon/about.png);}"
                    "QPushButton#btnAbout:hover{image: url(:/icon/icon/about-hover.png);}"
                    "QPushButton#btnMin{image: url(:/icon/icon/min.png);}"
                    "QPushButton#btnMin:hover{image: url(:/icon/icon/min-hover.png);"
                    "background-color: red;}"
                    "QPushButton#btnMax{image: url(:/icon/icon/max.png);}"
                    "QPushButton#btnMax:hover{image: url(:/icon/icon/max-hover.png);"
                    "background-color: red;}"
                    "QPushButton#btnClose{image: url(:/icon/icon/close.png);}"
                    "QPushButton#btnClose:hover{image: url(:/icon/icon/close-hover.png);"
                    "background-color: red;}"
                    "QFrame#frameLine{background-color: black;}";
    setStyleSheet(style);
*/
}

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

void JTitleBar::setTitleHeight(int height)
{
    if(m_titleHeight != height) {
        m_titleHeight = height;
        setFixedHeight(m_titleHeight);
        ui->btnLogo->setFixedHeight(m_titleHeight);
        for(auto btn : m_listNaviButtons) {
            btn->setFixedHeight(m_titleHeight);
//            btn->setFixedWidth(m_titleHeight * 3);
            btn->setTextAlign(JNaviButton::TextAlign_Center);
        }
    }
}

void JTitleBar::winStatus_changed()
{// 判断是鼠标左键
    if(NORMAL == m_winStatus) {// 当前处于正常状态则切换至最大化状态
        parentWidget()->setWindowState(Qt::WindowMaximized);
        m_winStatus = MAXIMIZED;
        return;
    }
    if(MAXIMIZED == m_winStatus){// 当前处于最大化状态则切换至正常状态
        parentWidget()->setWindowState(Qt::WindowNoState);
        m_winStatus = NORMAL;
        return;
    }
}

void JTitleBar::mousePressEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton) {
        m_startPos = event->pos();
        m_bLeftButtonPressed = true;
    }
}

void JTitleBar::mouseReleaseEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton) {
        m_bDragMax = false;
        m_bLeftButtonPressed = false;
    }
}

void JTitleBar::mouseMoveEvent(QMouseEvent *event)
{
    if(m_bLeftButtonPressed) {
        if(m_bDragMax) {
            return;
        }
        if(MAXIMIZED == m_winStatus){// 当前处于最大化状态时切换至正常状态
            parentWidget()->setWindowState(Qt::WindowNoState);
            m_winStatus = NORMAL;
//            QPoint p = event->pos() - m_startPos;
//            parentWidget()->move(parentWidget()->x() + p.x(), parentWidget()->y() + p.y());
        }
        else {
            if(event->globalY() <= 2) {// 判断距离屏幕顶部,距离小于 2 时切换至最大化状态
                parentWidget()->setWindowState(Qt::WindowMaximized);
                m_winStatus = MAXIMIZED;
                m_bDragMax = true;
                return;
            }
            else {// 正常移动窗口
                QPoint p = event->pos() - m_startPos;
                parentWidget()->move(parentWidget()->x() + p.x(), parentWidget()->y() + p.y());
            }
        }
    }
}

void JTitleBar::mouseDoubleClickEvent(QMouseEvent *event)
{
    if(event->button() == Qt::LeftButton) {
        winStatus_changed();
    }
}


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1214161.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

mysql数据库,sql语句中连接查询,连表查询,内连接,外连接,左外连接,右外连接,inner join、left join、right join,全连接

连表查询 现有多张表&#xff1a;员工表 emp&#xff08;员工编号、姓名、工资、部门号、经理编号&#xff09;、部门表 dept&#xff08;部门号、部门名称、部门位置&#xff09;、工资等级表 salgrade&#xff08;等级、工资下限、工资上限&#xff09; 连接查询&#xff1a;…

ClassLoader

Java /Android 默认ClassLoader是PathClassLoader Android 的 PathClassLoader 和DexClassLoader 都是BaseDexClassLoader的子类 BaseClassLoader是ClassLoader的子类,通过loadClass方法加载,Android将Java的ClassLoader简化了,第二个参数arg2 无效 loadClass 通过 findLoad…

搭建知识付费系统的最佳实践是什么

在数字化时代&#xff0c;搭建一个高效且用户友好的知识付费系统是许多创业者和内容创作者追求的目标。本文将介绍一些搭建知识付费系统的最佳实践&#xff0c;同时提供一些基本的技术代码示例&#xff0c;以帮助你快速入门。 1. 选择合适的技术栈&#xff1a; 搭建知识付费…

YOLO目标检测——烟叶病害检测数据集下载分享【含对应voc、coco和yolo三种格式标签】

实际项目应用&#xff1a;烟叶病虫害防治数据集说明&#xff1a;烟叶病害检测数据集&#xff0c;真实场景的高质量图片数据&#xff0c;数据场景丰富&#xff0c;类别分为&#xff1a;轻度病虫、中度病虫、高度病虫标签说明&#xff1a;使用lableimg标注软件标注&#xff0c;标…

微信群BUG大揭秘!开启身份切换神器

前言 最近微信群里出现了一个神秘的BUG&#xff0c;普通群成员竟然可以艾特全体成员。今天&#xff0c;就让我们一起揭秘这个令人震惊的微信群普通成员可全体成员的BUG 复现步骤 复现步骤也很简单&#xff0c;前提条件就是要在PC客户端操作&#xff01;首先得有个属于自己的群…

OCR文字识别标注小助手

目录 背景 工具界面 操作 1、选择目录 2、更改为正确的信息 3、保存 4、说明 项目 代码 下载 背景 为什么要写这么一个小工具呢&#xff1f;因为要对文字进行标注。 为什么对文字进行标注呢&#xff1f;因为要重新训练识别。 为什么要重新训练识别呢&#xff1f;因…

python socket编程2 - socket创建发送方所需参数的获得

使用socket进行进程间通信或者跨网络的计算机间通讯&#xff0c;有点类似日常生活中的发送快递。 根据发送方的需要&#xff0c;选择不同的物流公司&#xff1a; 在选择适合的公司和运输方式后&#xff0c;需要在app上做出选择&#xff0c;并根据要求填写一些信息。app会根据…

根据视频编码时间批量重命名视频文件

整理收藏的小视频的时候发现很多视频命名很随意&#xff0c;自己命名又太麻烦&#xff0c;看着乱糟糟的文件又心烦&#xff0c;所有写了这个程序&#xff0c;代码如下&#xff1a; import osfrom filetype import filetype from pymediainfo import MediaInfovideo_extension …

【文件读取/包含】任意文件读取漏洞 afr_3

1.1漏洞描述 漏洞名称任意文件读取漏洞 afr_3漏洞类型文件读取/包含漏洞等级⭐⭐⭐⭐⭐漏洞环境docker攻击方式 1.2漏洞等级 高危 1.3影响版本 暂无 1.4漏洞复现 1.4.1.基础环境 靶场docker工具BurpSuite 1.4.2.环境搭建 1.创建docker-compose.yml文件 version: 3.2 servi…

从CentOS向KeyarchOS操作系统的wordpress应用迁移实战

文章目录 从CentOS向KeyarchOS操作系统的wordpress应用迁移实战一、使用浪潮信息X2Keyarch迁移工具完成操作系统的迁移1.1 迁移前的验证1.2 执行迁移评估1.3 开始迁移1.4 验证迁移结果1.5 迁移后的验证 二、总结 从CentOS向KeyarchOS操作系统的wordpress应用迁移实战 CentOS是一…

mysql操作 sql语句中的完整性约束有哪些,主键约束、外键约束、引用完整性约束,主键外键、唯一性

什么是约束&#xff1a;约束&#xff1a;就是约定哪些东西能填、怎么填&#xff1f;哪些东西不能填&#xff1f; 文章目录 前言&#xff1a;建表正文一、实体完整性约束1. 主键约束2. 唯一性约束3. 自增长约束4. 联合主键约束 二、域完整性约束三、引用完整性约束1. 外键约束 讲…

【Git企业开发】第七节.多人协作开发

文章目录 前言 一、多人协作开发 1.1 多人协作一 1.2 多人协作二 1.3 远程分支删除后&#xff0c;本地 git branch -a 依然能看到的解决办法 总结 前言 一、多人协作开发 1.1 多人协作一 目前&#xff0c;我们所完成的工作如下: 基本完成Git的所有本地库的相关操作&#xff0…

未来10年,NAND 与DRAM依然是存储主角

根据Yole Group调查机构的数据显示&#xff0c;在2022年独立记忆体&#xff08;Stand-alone Memory&#xff09;整体市场达到了1440亿美元。其中DRAM占比55.4%&#xff0c;NAND占比40.8%。剩下的NOR、(NV)SRAM/FRAM、EEPROM、新型非易失存储(PCM, ReRAM and STT-MRAM)等占比3.8…

蓝桥杯 string

string简介 string是C标准库的重要组成部分&#xff0c;主要用于字符串处理。 使用string库需要在头文件中包括该库 #include< string> string与char[]不同&#xff0c;string实现了高度的封装&#xff0c;可以很方便地完 成各种字符串的操作&#xff0c;比如拼接、截取…

Since Maven 3.8.1 http repositories are blocked

原因 高版本的maven不支持http的存储库。 解决方案 其实方法有好几种&#xff0c;比如降级maven版本至3.6.3(之前一直用的都是这个版本)&#xff0c;我选择了一种比较快(但不一定安全)的方式&#xff0c;因为3.6.3版本被我卸载了&#xff0c;这里直接修改idea的setting配置&…

【Java 进阶篇】JQuery 案例:下拉列表选中条目左右移动,打破选择的边界

在前端的舞台上&#xff0c;下拉列表是常见的用户交互元素&#xff0c;但有时候我们想要更多的交互体验。通过巧妙运用 JQuery&#xff0c;我们可以实现下拉列表中选中条目的左右移动功能&#xff0c;为用户提供更加灵活的选择方式。本篇博客将深入研究 JQuery 中实现这一功能的…

技巧篇:在Pycharm中配置集成Git

一、在Pycharm中配置集成Git 我们使用git需要先安装git工具&#xff0c;这里给出下载地址&#xff0c;下载后一路直接安装即可&#xff1a; https://git-for-windows.github.io/ 0. git中的一些常用词释义 Repository name&#xff1a; 仓库名称 Description(可选)&#xff1a;…

【数据结构】别跟我讲你不会冒泡排序

&#x1f466;个人主页&#xff1a;Weraphael ✍&#x1f3fb;作者简介&#xff1a;目前正在学习c和算法 ✈️专栏&#xff1a;数据结构 &#x1f40b; 希望大家多多支持&#xff0c;咱一起进步&#xff01;&#x1f601; 如果文章有啥瑕疵 希望大佬指点一二 如果文章对你有帮助…

旅拍摄影技巧澳大利亚、韩国旅行攻略

欢迎关注「苏南下」 在这里分享我的旅行和影像创作心得 刚刚在腾讯内部做了一场摄影分享课&#xff1a; 《旅拍摄影技巧&澳大利亚、韩国旅行攻略》 分享了早前去两个国家的一些旅行见闻和摄影心得。我发现&#xff1a;把自己学会的东西整理出来&#xff0c;再告诉给别人这件…

67基于matlab图像处理,包括颜色和亮度调整、翻转功能、空间滤波和去噪、频域滤波和去噪、噪声添加,形态学操作、边缘检测及示波器集成的GUI图像处理。

基于matlab图像处理&#xff0c;包括颜色和亮度调整、翻转功能、空间滤波和去噪、频域滤波和去噪、噪声添加&#xff0c;形态学操作、边缘检测及示波器集成的GUI图像处理。数据可更换自己的&#xff0c;程序已调通&#xff0c;可直接运行。 67 matlab图像处理图像降噪 (xiaohon…